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

Last change on this file since 5232 was 5206, checked in by xwa163, 3 years ago
  1. Extend Regex Syntax, include: (a) RL2.6 of UTS#18, support regex in property value. e.g. \p{script=/.*hir.*/} (b) Support syntax of property expression when parsing boundary. e.g. \b{greek} (c) Extend property expression in non capture group. e.g. (?\p{upper}:\p{greek}\p{script=hira})
  2. Add related test cases
File size: 13.7 KB
RevLine 
[4380]1/*
[4388]2 *  Copyright (c) 2015 International Characters.
[4380]3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
[4660]6#include "resolve_properties.h"
[4380]7#include <re/re_alt.h>
[4626]8#include <re/re_any.h>
[4380]9#include <re/re_name.h>
10#include <re/re_diff.h>
[5091]11#include <re/re_any.h>
12#include <re/re_start.h>
13#include <re/re_end.h>
14#include <re/re_cc.h>
15#include <re/re_seq.h>
16#include <re/re_rep.h>
17#include <re/re_intersect.h>
18#include <re/re_assertion.h>
[4380]19#include "UCD/PropertyAliases.h"
20#include "UCD/PropertyObjects.h"
21#include "UCD/PropertyObjectTable.h"
22#include "UCD/PropertyValueAliases.h"
[4660]23#include <string>
24#include <iostream>
[4380]25
[4618]26using namespace UCD;
[4626]27using namespace re;
[4390]28
[4380]29
[4627]30inline int GetPropertyValueEnumCode(const UCD::property_t type, const std::string & value) {
31    return property_object_table[type]->GetPropertyValueEnumCode(value);
32}
33
[4673]34namespace UCD {
35
[5091]36void generateGraphemeClusterBoundaryRule(Name * const &property) {
37    // 3.1.1 Grapheme Cluster Boundary Rules
38#define Behind(x) makeLookBehindAssertion(x)
39#define Ahead(x) makeLookAheadAssertion(x)
40
41    RE * GCB_Control = makeName("gcb", "cn", Name::Type::UnicodeProperty);
42    RE * GCB_CR = makeName("gcb", "cr", Name::Type::UnicodeProperty);
43    RE * GCB_LF = makeName("gcb", "lf", Name::Type::UnicodeProperty);
44    RE * GCB_Control_CR_LF = makeAlt({GCB_CR, GCB_LF});
45
46    // Break at the start and end of text.
47    RE * GCB_1 = makeStart();
48    RE * GCB_2 = makeEnd();
49    // Do not break between a CR and LF.
50    RE * GCB_3 = makeSeq({Behind(GCB_CR), Ahead(GCB_LF)});
51    // Otherwise, break before and after controls.
52    RE * GCB_4 = Behind(GCB_Control_CR_LF);
53    RE * GCB_5 = Ahead(GCB_Control_CR_LF);
54    RE * GCB_1_5 = makeAlt({GCB_1, GCB_2, makeDiff(makeAlt({GCB_4, GCB_5}), GCB_3)});
55
56    RE * GCB_L = makeName("gcb", "l", Name::Type::UnicodeProperty);
57    RE * GCB_V = makeName("gcb", "v", Name::Type::UnicodeProperty);
58    RE * GCB_LV = makeName("gcb", "lv", Name::Type::UnicodeProperty);
59    RE * GCB_LVT = makeName("gcb", "lvt", Name::Type::UnicodeProperty);
60    RE * GCB_T = makeName("gcb", "t", Name::Type::UnicodeProperty);
61    RE * GCB_RI = makeName("gcb", "ri", Name::Type::UnicodeProperty);
62    // Do not break Hangul syllable sequences.
63    RE * GCB_6 = makeSeq({Behind(GCB_L), Ahead(makeAlt({GCB_L, GCB_V, GCB_LV, GCB_LVT}))});
64    RE * GCB_7 = makeSeq({Behind(makeAlt({GCB_LV, GCB_V})), Ahead(makeAlt({GCB_V, GCB_T}))});
65    RE * GCB_8 = makeSeq({Behind(makeAlt({GCB_LVT, GCB_T})), Ahead(GCB_T)});
66    // Do not break between regional indicator symbols.
67    RE * GCB_8a = makeSeq({Behind(GCB_RI), Ahead(GCB_RI)});
68    // Do not break before extending characters.
69    RE * GCB_9 = Ahead(makeName("gcb", "ex", Name::Type::UnicodeProperty));
70    // Do not break before SpacingMarks, or after Prepend characters.
71    RE * GCB_9a = Ahead(makeName("gcb", "sm", Name::Type::UnicodeProperty));
72    RE * GCB_9b = Behind(makeName("gcb", "pp", Name::Type::UnicodeProperty));
73    RE * GCB_6_9b = makeAlt({GCB_6, GCB_7, GCB_8, GCB_8a, GCB_9, GCB_9a, GCB_9b});
74    // Otherwise, break everywhere.
75    RE * GCB_10 = makeSeq({Behind(makeAny()), Ahead(makeAny())});
76
77    //Name * gcb = makeName("gcb", Name::Type::UnicodeProperty);
78    property->setDefinition(makeAlt({GCB_1_5, makeDiff(GCB_10, GCB_6_9b)}));
79}
80
[4814]81bool resolvePropertyDefinition(Name * const property) {
[4809]82    if (property->hasNamespace()) {
83        auto propit = alias_map.find(property->getNamespace());
84        if (propit == alias_map.end()) {
85            throw UnicodePropertyExpressionError("Expected a property name but '" + property->getNamespace() + "' was found instead");
86        }
87        auto theprop = propit->second;
88        if (isa<BinaryPropertyObject>(property_object_table[theprop])){
89            auto valit = Binary_ns::aliases_only_map.find(property->getName());
90            if (valit != Binary_ns::aliases_only_map.end()) {
91                if (valit->second == Binary_ns::N) {
92                    Name * binprop = makeName(property_enum_name[theprop], Name::Type::UnicodeProperty);
93                    property->setDefinition(makeDiff(makeAny(), binprop));
[4814]94                    return true;
[4809]95                }
96            }
97        }
98    } else {
99        const std::string value = property->getName();
100        // Try special cases of Unicode TR #18
101        if (value == "any") {
102            property->setDefinition(makeAny());
[4814]103            return true;
104        } else if (value == "ascii") {
[4809]105            property->setDefinition(makeName("blk", "ascii", Name::Type::UnicodeProperty));
[4814]106            return true;
107        } else if (value == "assigned") {
[4809]108            Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
109            property->setDefinition(makeDiff(makeAny(), unassigned));
[4814]110            return true;
[4809]111        }
112        // Now compatibility properties of UTR #18 Annex C
113        else if (value == "xdigit") {
114            Name * digit = makeName("nd", Name::Type::UnicodeProperty);
115            Name * hexdigit = makeName("hexdigit", Name::Type::UnicodeProperty);
116            property->setDefinition(makeAlt({digit, hexdigit}));
[4814]117            return true;
118        } else if (value == "alnum") {
[4809]119            Name * digit = makeName("nd", Name::Type::UnicodeProperty);
120            Name * alpha = makeName("alphabetic", Name::Type::UnicodeProperty);
121            property->setDefinition(makeAlt({digit, alpha}));
[4814]122            return true;
123        } else if (value == "blank") {
[4809]124            Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
125            CC * tab = makeCC(0x09);
126            property->setDefinition(makeAlt({space_sep, tab}));
[4814]127            return true;
128        } else if (value == "graph") {
[4809]129            Name * space = makeName("space", Name::Type::UnicodeProperty);
130            Name * ctrl = makeName("control", Name::Type::UnicodeProperty);
131            Name * surr = makeName("surrogate", Name::Type::UnicodeProperty);
132            Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
133            property->setDefinition(makeDiff(makeAny(), makeAlt({space, ctrl, surr, unassigned})));
[4814]134            return true;
135        } else if (value == "print") {
[4809]136            Name * graph = makeName("graph", Name::Type::UnicodeProperty);
137            Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
138            property->setDefinition(makeAlt({graph, space_sep}));
[4814]139            return true;
140        } else if (value == "word") {
[4809]141            Name * alnum = makeName("alnum", Name::Type::UnicodeProperty);
142            Name * mark = makeName("mark", Name::Type::UnicodeProperty);
143            Name * conn = makeName("connectorpunctuation", Name::Type::UnicodeProperty);
144            Name * join = makeName("joincontrol", Name::Type::UnicodeProperty);
145            property->setDefinition(makeAlt({alnum, mark, conn, join}));
[4814]146            return true;
[5091]147        } else if (value == "GCB" || value == "NonGCB"){
148            generateGraphemeClusterBoundaryRule(property);
149            return true;
[4809]150        }
[4673]151    }
[4814]152    return false;
[4809]153}
[4673]154
[4809]155std::string resolvePropertyFunction(Name * const property) {
156    const std::string value = property->getName();
157    std::string functionName;
158    if (property->hasNamespace()) {
159        auto propit = alias_map.find(property->getNamespace());
160        if (propit == alias_map.end()) {
161            throw UnicodePropertyExpressionError("Expected a property name but '" + property->getNamespace() + "' was found instead");
[4380]162        }
[4809]163        auto theprop = propit->second;
164        if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
165            int valcode = p->GetPropertyValueEnumCode(value);
166            if (valcode < 0) {
167                throw UnicodePropertyExpressionError("Erroneous property value '" + value + "' for " + property_full_name[theprop] + " property");
168            }
169            functionName = "__get_" + property_enum_name[theprop] + "_" + p->GetValueEnumName(valcode);
[4660]170        }
[4809]171        else if (theprop == scx) {
172            // Script extension property identified
173            int valcode = GetPropertyValueEnumCode(sc, value);
174            if (valcode < 0) {
175                throw UnicodePropertyExpressionError("Erroneous property value for script_extension property");
176            }
177            functionName = "__get_scx_" + SC_ns::enum_names[valcode];
[4660]178        }
[4809]179        else if (isa<BinaryPropertyObject>(property_object_table[theprop])){
180            auto valit = Binary_ns::aliases_only_map.find(value);
181            if (valit == Binary_ns::aliases_only_map.end()) {
182                throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
183            }
184            if (valit->second == Binary_ns::Y) {
185                functionName = "__get_" + property_enum_name[theprop] + "_Y";
186            } else {
187                throw UnicodePropertyExpressionError("Unexpected property value for binary property " + property_full_name[theprop]);
188            }
[4660]189        }
190        else {
[4809]191            throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
[4660]192        }
[4809]193    } else { // No namespace (property) name.
194        // Try as a general category, script or binary property.
[4661]195        int valcode;
196        if ((valcode = GetPropertyValueEnumCode(gc, value)) >= 0) {
[4809]197            functionName = "__get_gc_" + GC_ns::enum_names[valcode];
[4380]198        }
[4673]199        else if ((valcode = GetPropertyValueEnumCode(sc, value)) >= 0) {
[4809]200            functionName = "__get_sc_" + SC_ns::enum_names[valcode];
[4660]201        }
[4673]202        else { // Try as a binary property.
203            auto propit = alias_map.find(value);
204            if (propit != alias_map.end()) {
205                auto theprop = propit->second;
206                if (isa<BinaryPropertyObject>(property_object_table[theprop])) {
[4809]207                    functionName = "__get_" + property_enum_name[theprop] + "_Y";
[4673]208                }
209                else {
210                    throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
211                }
[4660]212            }
213            else {
[4673]214                throw UnicodePropertyExpressionError("Expected a general category, script or binary property name but '" + value + "' was found instead");
[4660]215            }
216        }
[4380]217    }
[4809]218    assert (functionName.length() > 0);
[5037]219    return functionName;
[4380]220}
221
[5206]222const std::string& getPropertyValueGrepString(const std::string & prop) {
223    auto propName = canonicalize_value_name(prop);
224    auto propit = alias_map.find(propName);
225    if (propit == alias_map.end()) {
226        throw UnicodePropertyExpressionError("Expected a property name, but '" + prop + "' found instead");
227    }
228    auto theprop = propit->second;
229    if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
230        return p->GetPropertyValueGrepString();
231    } else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
232        return p->GetPropertyValueGrepString();
233    }
234
235    throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
236}
237
[4626]238UnicodeSet resolveUnicodeSet(Name * const name) {
239    if (name->getType() == Name::Type::UnicodeProperty) {
240        std::string prop = name->getNamespace();
241        std::string value = canonicalize_value_name(name->getName());
242        if (prop.length() > 0) {
243            prop = canonicalize_value_name(prop);
244            auto propit = alias_map.find(prop);
245            if (propit == alias_map.end()) {
246                throw UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
247            }
[4631]248            auto theprop = propit->second;
[4735]249            if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
250                return p->GetCodepointSet(value);
[4626]251            }
[4631]252            else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])){
[4626]253                auto valit = Binary_ns::aliases_only_map.find(value);
254                if (valit == Binary_ns::aliases_only_map.end()) {
255                    throw UnicodePropertyExpressionError("Erroneous property value for binary property " + property_full_name[theprop]);
256                }
[4631]257                return p->GetCodepointSet(value);
258            }           
[4626]259            throw UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
260        }
261        else {
262            // No namespace (property) name.   Try as a general category.
[4627]263            int valcode = GetPropertyValueEnumCode(gc, value);
[4626]264            if (valcode >= 0) {
265                return cast<EnumeratedPropertyObject>(property_object_table[gc])->GetCodepointSet(valcode);
266            }
[4631]267            valcode = GetPropertyValueEnumCode(sc, value);
[4626]268            if (valcode >= 0) {
269                return cast<EnumeratedPropertyObject>(property_object_table[sc])->GetCodepointSet(valcode);
270            }
271            // Try as a binary property.
272            auto propit = alias_map.find(value);
273            if (propit != alias_map.end()) {
[4631]274                auto theprop = propit->second;
275                if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
276                    return p->GetCodepointSet(Binary_ns::Y);
[4626]277                }
278                else {
279                    throw UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
280                }
281            }
282        }
283    }
284    throw UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
285}
[4673]286
287}
Note: See TracBrowser for help on using the repository browser.