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

Last change on this file since 5872 was 5872, checked in by cameron, 14 months ago

Decoupling CC compilers from Pablo Kernel

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