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

Last change on this file since 5787 was 5787, checked in by cameron, 7 months ago

RE parser restructuring; parsing symbolic ranges, collation and equivalence exprs

File size: 11.7 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 <re/re_re.h>
7#include "resolve_properties.h"
8#include <re/re_alt.h>
9#include <re/re_any.h>
10#include <re/re_name.h>
11#include <re/re_diff.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_assertion.h>
17#include <re/re_parser.h>
18#include <re/re_name_resolve.h>
19#include <re/re_compiler.h>
20#include "UCD/PropertyAliases.h"
21#include "UCD/PropertyObjects.h"
22#include "UCD/PropertyObjectTable.h"
23#include "UCD/PropertyValueAliases.h"
24#include <llvm/Support/ErrorHandling.h>
25
26using namespace UCD;
27using namespace re;
28using namespace llvm;
29
30namespace UCD {
31   
32void UnicodePropertyExpressionError(std::string errmsg) {
33    llvm::report_fatal_error(errmsg);
34}
35
36#define Behind(x) makeLookBehindAssertion(x)
37#define Ahead(x) makeLookAheadAssertion(x)
38
39void generateGraphemeClusterBoundaryRule(Name * const &property) {
40    // 3.1.1 Grapheme Cluster Boundary Rules
41
42//    RE * GCB_Control = makeName("gcb", "cn", Name::Type::UnicodeProperty);
43    RE * GCB_CR = makeName("gcb", "cr", Name::Type::UnicodeProperty);
44    RE * GCB_LF = makeName("gcb", "lf", Name::Type::UnicodeProperty);
45    RE * GCB_Control_CR_LF = makeAlt({GCB_CR, GCB_LF});
46
47    // Break at the start and end of text.
48    RE * GCB_1 = makeStart();
49    RE * GCB_2 = makeEnd();
50    // Do not break between a CR and LF.
51    RE * GCB_3 = makeSeq({Behind(GCB_CR), Ahead(GCB_LF)});
52    // Otherwise, break before and after controls.
53    RE * GCB_4 = Behind(GCB_Control_CR_LF);
54    RE * GCB_5 = Ahead(GCB_Control_CR_LF);
55    RE * GCB_1_5 = makeAlt({GCB_1, GCB_2, makeDiff(makeAlt({GCB_4, GCB_5}), GCB_3)});
56
57    RE * GCB_L = makeName("gcb", "l", Name::Type::UnicodeProperty);
58    RE * GCB_V = makeName("gcb", "v", Name::Type::UnicodeProperty);
59    RE * GCB_LV = makeName("gcb", "lv", Name::Type::UnicodeProperty);
60    RE * GCB_LVT = makeName("gcb", "lvt", Name::Type::UnicodeProperty);
61    RE * GCB_T = makeName("gcb", "t", Name::Type::UnicodeProperty);
62    RE * GCB_RI = makeName("gcb", "ri", Name::Type::UnicodeProperty);
63    // Do not break Hangul syllable sequences.
64    RE * GCB_6 = makeSeq({Behind(GCB_L), Ahead(makeAlt({GCB_L, GCB_V, GCB_LV, GCB_LVT}))});
65    RE * GCB_7 = makeSeq({Behind(makeAlt({GCB_LV, GCB_V})), Ahead(makeAlt({GCB_V, GCB_T}))});
66    RE * GCB_8 = makeSeq({Behind(makeAlt({GCB_LVT, GCB_T})), Ahead(GCB_T)});
67    // Do not break between regional indicator symbols.
68    RE * GCB_8a = makeSeq({Behind(GCB_RI), Ahead(GCB_RI)});
69    // Do not break before extending characters.
70    RE * GCB_9 = Ahead(makeName("gcb", "ex", Name::Type::UnicodeProperty));
71    // Do not break before SpacingMarks, or after Prepend characters.
72    RE * GCB_9a = Ahead(makeName("gcb", "sm", Name::Type::UnicodeProperty));
73    RE * GCB_9b = Behind(makeName("gcb", "pp", Name::Type::UnicodeProperty));
74    RE * GCB_6_9b = makeAlt({GCB_6, GCB_7, GCB_8, GCB_8a, GCB_9, GCB_9a, GCB_9b});
75    // Otherwise, break everywhere.
76    RE * GCB_10 = makeSeq({Behind(makeAny()), Ahead(makeAny())});
77
78    //Name * gcb = makeName("gcb", Name::Type::UnicodeProperty);
79    property->setDefinition(makeAlt({GCB_1_5, makeDiff(GCB_10, GCB_6_9b)}));
80}
81
82bool resolvePropertyDefinition(Name * const property) {
83    if (property->hasNamespace()) {
84        auto propit = alias_map.find(property->getNamespace());
85        if (propit == alias_map.end()) {
86            UnicodePropertyExpressionError("Expected a property name but '" + property->getNamespace() + "' was found instead");
87        }
88        auto theprop = propit->second;
89        if (isa<BinaryPropertyObject>(property_object_table[theprop])){
90            auto valit = Binary_ns::aliases_only_map.find(property->getName());
91            if (valit != Binary_ns::aliases_only_map.end()) {
92                if (valit->second == Binary_ns::N) {
93                    Name * binprop = makeName(property_enum_name[theprop], Name::Type::UnicodeProperty);
94                    property->setDefinition(makeDiff(makeAny(), binprop));
95                    return true;
96                }
97            }
98        }
99    } else {
100        const std::string value = property->getName();
101        // Try special cases of Unicode TR #18
102        if ((value == "any") || (value == ".")) {
103            property->setDefinition(makeCC(0, 0x10FFFF));
104            return true;
105        } else if (value == "ascii") {
106            property->setDefinition(makeName("blk", "ascii", Name::Type::UnicodeProperty));
107            return true;
108        } else if (value == "assigned") {
109            Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
110            property->setDefinition(makeDiff(makeAny(), unassigned));
111            return true;
112        } else if (value == "\\b{g}" || value == "\\B{g}") {
113            generateGraphemeClusterBoundaryRule(property);
114            return true;
115        } else if (value == "^s") {  // "start anchor (^) in single-line mode"
116            property->setDefinition(makeNegativeLookBehindAssertion(makeCC(0, 0x10FFFF)));
117            return true;
118        } else if (value == "$s") { // "end anchor ($) in single-line mode"
119            property->setDefinition(makeNegativeLookAheadAssertion(makeCC(0, 0x10FFFF)));
120            return true;
121        }
122    }
123    return false;
124}
125
126const std::string & getPropertyValueGrepString(const std::string & prop) {
127    auto propit = alias_map.find(canonicalize_value_name(prop));
128    if (propit == alias_map.end()) {
129        UnicodePropertyExpressionError("Expected a property name, but '" + prop + "' found instead");
130    }
131    auto theprop = propit->second;
132    if (EnumeratedPropertyObject * p = dyn_cast<EnumeratedPropertyObject>(property_object_table[theprop])){
133        return p->GetPropertyValueGrepString();
134    } else if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
135        return p->GetPropertyValueGrepString();
136    }
137
138    UnicodePropertyExpressionError("Property " + property_full_name[theprop] + " recognized but not supported in icgrep 1.0");
139}
140
141UnicodeSet resolveUnicodeSet(Name * const name) {
142    if (name->getType() == Name::Type::UnicodeProperty) {
143        std::string prop = name->getNamespace();
144        std::string value = name->getName();
145        if (prop.length() > 0) {
146            prop = canonicalize_value_name(prop);
147            auto propit = alias_map.find(prop);
148            if (propit == alias_map.end()) {
149                UnicodePropertyExpressionError("Expected a property name, but '" + name->getNamespace() + "' found instead");
150            }
151            auto propObj = property_object_table[propit->second];
152            if ((value.length() > 0) && (value[0] == '/')) {
153                // resolve a regular expression
154                re::RE * propValueRe = RE_Parser::parse(value.substr(1), re::DEFAULT_MODE, re::PCRE, false);
155                propValueRe = re::resolveNames(propValueRe);  // Recursive name resolution may be required.
156                return propObj->GetCodepointSetMatchingPattern(propValueRe);
157            }
158            if ((value.length() > 0) && (value[0] == '@')) {
159                // resolve a @property@ or @identity@ expression.
160                std::string otherProp = canonicalize_value_name(value.substr(1));
161                if (otherProp == "identity") {
162                    return propObj->GetReflexiveSet();
163                }
164                auto propit = alias_map.find(prop);
165                if (propit == alias_map.end()) {
166                    UnicodePropertyExpressionError("Expected a property name, but '" + value.substr(1) + "' found instead");
167                }
168                auto propObj2 = property_object_table[propit->second];
169                if (isa<BinaryPropertyObject>(propObj) && isa<BinaryPropertyObject>(propObj2)) {
170                    return ~(cast<BinaryPropertyObject>(propObj)->GetCodepointSet(UCD::Binary_ns::Y) ^
171                             cast<BinaryPropertyObject>(propObj2)->GetCodepointSet(UCD::Binary_ns::Y));
172                }
173                else {
174                    UnicodePropertyExpressionError("unsupported");
175                }
176            }
177            else {
178                return propObj->GetCodepointSet(value);
179            }
180        }
181        else {
182            // No namespace (property) name.   Try as a general category.
183            const auto & gcobj = cast<EnumeratedPropertyObject>(property_object_table[gc]);
184            int valcode = gcobj->GetPropertyValueEnumCode(value);
185            if (valcode >= 0) {
186                return gcobj->GetCodepointSet(valcode);
187            }
188            const auto & scObj = cast<EnumeratedPropertyObject>(property_object_table[sc]);
189            valcode = scObj->GetPropertyValueEnumCode(value);
190            if (valcode >= 0) {
191                return scObj->GetCodepointSet(valcode);
192            }
193            // Try as a binary property.
194            auto propit = alias_map.find(value);
195            if (propit != alias_map.end()) {
196                auto theprop = propit->second;
197                if (BinaryPropertyObject * p = dyn_cast<BinaryPropertyObject>(property_object_table[theprop])) {
198                    return p->GetCodepointSet(Binary_ns::Y);
199                }
200                else {
201                    UnicodePropertyExpressionError("Error: property " + property_full_name[theprop] + " specified without a value");
202                }
203            }
204            // Try special cases of Unicode TR #18
205            // Now compatibility properties of UTR #18 Annex C
206                   
207            else if (value == ".") return UnicodeSet(0, 0x10FFFF);
208            else if (value == "alnum") {
209                Name * digit = makeName("nd", Name::Type::UnicodeProperty);
210                Name * alpha = makeName("alphabetic", Name::Type::UnicodeProperty);
211                return resolveUnicodeSet(digit) + resolveUnicodeSet(alpha);
212            } else if (value == "xdigit") {
213                Name * digit = makeName("nd", Name::Type::UnicodeProperty);
214                Name * hexdigit = makeName("hexdigit", Name::Type::UnicodeProperty);
215                return resolveUnicodeSet(digit) + resolveUnicodeSet(hexdigit);
216            } else if (value == "blank") {
217                Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
218                return resolveUnicodeSet(space_sep) + UnicodeSet(0x09) /* tab */;
219            } else if (value == "print") {
220                Name * graph = makeName("graph", Name::Type::UnicodeProperty);
221                Name * space_sep = makeName("space_separator", Name::Type::UnicodeProperty);
222                return resolveUnicodeSet(graph) + resolveUnicodeSet(space_sep);
223            } else if (value == "word") {
224                Name * alnum = makeName("alnum", Name::Type::UnicodeProperty);
225                Name * mark = makeName("mark", Name::Type::UnicodeProperty);
226                Name * conn = makeName("connectorpunctuation", Name::Type::UnicodeProperty);
227                Name * join = makeName("joincontrol", Name::Type::UnicodeProperty);
228                return resolveUnicodeSet(alnum) + resolveUnicodeSet(mark) + resolveUnicodeSet(conn) + resolveUnicodeSet(join);
229            } else if (value == "graph") {
230                Name * space = makeName("space", Name::Type::UnicodeProperty);
231                Name * ctrl = makeName("control", Name::Type::UnicodeProperty);
232                Name * surr = makeName("surrogate", Name::Type::UnicodeProperty);
233                Name * unassigned = makeName("cn", Name::Type::UnicodeProperty);
234                return ~(resolveUnicodeSet(space) + resolveUnicodeSet(ctrl) + resolveUnicodeSet(surr) + resolveUnicodeSet(unassigned));
235            }
236
237
238        }
239    }
240    UnicodePropertyExpressionError("Expected a general category, script or binary property name, but '" + name->getName() + "' found instead");
241}
242
243}
Note: See TracBrowser for help on using the repository browser.