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

Last change on this file since 4742 was 4737, checked in by cameron, 4 years ago

Handle arbitrary enumerated properties without special casing; improve error reporting

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