/src/icu/icu4c/source/common/rbbistbl.cpp
Line | Count | Source |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | // |
4 | | // file: rbbistbl.cpp Implementation of the ICU RBBISymbolTable class |
5 | | // |
6 | | /* |
7 | | *************************************************************************** |
8 | | * Copyright (C) 2002-2014 International Business Machines Corporation |
9 | | * and others. All rights reserved. |
10 | | *************************************************************************** |
11 | | */ |
12 | | |
13 | | #include "unicode/utypes.h" |
14 | | |
15 | | #if !UCONFIG_NO_BREAK_ITERATION |
16 | | |
17 | | #include "unicode/unistr.h" |
18 | | #include "unicode/uniset.h" |
19 | | #include "unicode/uchar.h" |
20 | | #include "unicode/parsepos.h" |
21 | | |
22 | | #include "cstr.h" |
23 | | #include "rbbinode.h" |
24 | | #include "rbbirb.h" |
25 | | #include "umutex.h" |
26 | | |
27 | | |
28 | | // |
29 | | // RBBISymbolTableEntry_deleter Used by the UHashTable to delete the contents |
30 | | // when the hash table is deleted. |
31 | | // |
32 | | U_CDECL_BEGIN |
33 | 0 | static void U_CALLCONV RBBISymbolTableEntry_deleter(void *p) { |
34 | 0 | icu::RBBISymbolTableEntry *px = (icu::RBBISymbolTableEntry *)p; |
35 | 0 | delete px; |
36 | 0 | } |
37 | | U_CDECL_END |
38 | | |
39 | | |
40 | | |
41 | | U_NAMESPACE_BEGIN |
42 | | |
43 | | RBBISymbolTable::RBBISymbolTable(RBBIRuleScanner *rs, const UnicodeString &rules, UErrorCode &status) |
44 | 0 | : fRules(rules), fRuleScanner(rs) |
45 | 0 | { |
46 | 0 | fHashTable = nullptr; |
47 | |
|
48 | 0 | fHashTable = uhash_open(uhash_hashUnicodeString, uhash_compareUnicodeString, nullptr, &status); |
49 | | // uhash_open checks status |
50 | 0 | if (U_FAILURE(status)) { |
51 | 0 | return; |
52 | 0 | } |
53 | 0 | uhash_setValueDeleter(fHashTable, RBBISymbolTableEntry_deleter); |
54 | 0 | } |
55 | | |
56 | | |
57 | | |
58 | | RBBISymbolTable::~RBBISymbolTable() |
59 | 0 | { |
60 | 0 | uhash_close(fHashTable); |
61 | 0 | } |
62 | | |
63 | | |
64 | | // |
65 | | // RBBISymbolTable::lookup This function from the abstract symbol table interface |
66 | | // looks up a variable name and returns a UnicodeString |
67 | | // containing the substitution text. |
68 | | // |
69 | | // The variable name does NOT include the leading $. |
70 | | // |
71 | | const UnicodeString *RBBISymbolTable::lookup(const UnicodeString& s) const |
72 | 0 | { |
73 | 0 | const RBBISymbolTableEntry* const el = |
74 | 0 | static_cast<const RBBISymbolTableEntry*>(uhash_get(fHashTable, &s)); |
75 | 0 | if (el == nullptr) { |
76 | 0 | return nullptr; |
77 | 0 | } |
78 | 0 | const RBBINode& exprNode = *el->val->fLeftChild; // Root node of expression for variable |
79 | | // Return the original source string for the expression. |
80 | | // Note that for set-valued variables used in UnicodeSet expressions, this would be rejected by |
81 | | // the UnicodeSet parser if the source itself contains variable references. For instance, with |
82 | | // $CaseIgnorable = [[:Mn:][:Me:][:Cf:][:Lm:][:Sk:] \u0027 \u00AD \u2019]; |
83 | | // $Cased = [[:Upper_Case:][:Lower_Case:][:Lt:] - $CaseIgnorable]; |
84 | | // If lookupSet were not overridden, when parsing the right-hand side of |
85 | | // $NotCased = [[^ $Cased] - $CaseIgnorable]; |
86 | | // there would be a call to lookup("Cased") which would return |
87 | | // "[[:Upper_Case:][:Lower_Case:][:Lt:]-$CaseIgnorable]". This contains a variable, which is |
88 | | // disallowed by the UnicodeSet parser inside a variable expansion. |
89 | | // However, set-valued variables are pre-parsed, and returned by lookupSet instead, so this call |
90 | | // to lookup() never happens; instead, lookupSet("CaseIgnorable") is called when computing |
91 | | // $Cased and returns the non-null value of $CaseIgnorable, and then when computing $NotCased, |
92 | | // lookupSet("Cased") returns the value computed for $Cased. |
93 | 0 | return &exprNode.fText; |
94 | 0 | } |
95 | | |
96 | 0 | const UnicodeSet* RBBISymbolTable::lookupSet(const UnicodeString& s) const { |
97 | 0 | const RBBISymbolTableEntry* const el = static_cast<const RBBISymbolTableEntry*>(uhash_get(fHashTable, &s)); |
98 | 0 | if (el == nullptr) { |
99 | 0 | return nullptr; |
100 | 0 | } |
101 | 0 | const RBBINode& exprNode = *el->val->fLeftChild; |
102 | 0 | if (exprNode.fType == RBBINode::setRef) { |
103 | 0 | return exprNode.fLeftChild->fInputSet; |
104 | 0 | } else { |
105 | 0 | return nullptr; |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | | |
110 | | |
111 | | // No longer used, see ICU-23297. |
112 | 0 | const UnicodeFunctor* RBBISymbolTable::lookupMatcher(UChar32 /*ch*/) const { |
113 | 0 | return nullptr; |
114 | 0 | } |
115 | | |
116 | | // |
117 | | // RBBISymbolTable::parseReference This function from the abstract symbol table interface |
118 | | // looks for a $variable name in the source text. |
119 | | // It does not look it up, only scans for it. |
120 | | // It is used by the UnicodeSet parser. |
121 | | // |
122 | | // This implementation is lifted pretty much verbatim |
123 | | // from the rules based transliterator implementation. |
124 | | // I didn't see an obvious way of sharing it. |
125 | | // |
126 | | UnicodeString RBBISymbolTable::parseReference(const UnicodeString& text, |
127 | | ParsePosition& pos, int32_t limit) const |
128 | 0 | { |
129 | 0 | int32_t start = pos.getIndex(); |
130 | 0 | int32_t i = start; |
131 | 0 | UnicodeString result; |
132 | 0 | while (i < limit) { |
133 | 0 | char16_t c = text.charAt(i); |
134 | 0 | if ((i==start && !u_isIDStart(c)) || !u_isIDPart(c)) { |
135 | 0 | break; |
136 | 0 | } |
137 | 0 | ++i; |
138 | 0 | } |
139 | 0 | if (i == start) { // No valid name chars |
140 | 0 | return result; // Indicate failure with empty string |
141 | 0 | } |
142 | 0 | pos.setIndex(i); |
143 | 0 | text.extractBetween(start, i, result); |
144 | 0 | return result; |
145 | 0 | } |
146 | | |
147 | | |
148 | | |
149 | | // |
150 | | // RBBISymbolTable::lookupNode Given a key (a variable name), return the |
151 | | // corresponding RBBI Node. If there is no entry |
152 | | // in the table for this name, return nullptr. |
153 | | // |
154 | 0 | RBBINode *RBBISymbolTable::lookupNode(const UnicodeString &key) const{ |
155 | |
|
156 | 0 | RBBINode *retNode = nullptr; |
157 | 0 | RBBISymbolTableEntry *el; |
158 | |
|
159 | 0 | el = static_cast<RBBISymbolTableEntry*>(uhash_get(fHashTable, &key)); |
160 | 0 | if (el != nullptr) { |
161 | 0 | retNode = el->val; |
162 | 0 | } |
163 | 0 | return retNode; |
164 | 0 | } |
165 | | |
166 | | |
167 | | // |
168 | | // RBBISymbolTable::addEntry Add a new entry to the symbol table. |
169 | | // Indicate an error if the name already exists - |
170 | | // this will only occur in the case of duplicate |
171 | | // variable assignments. |
172 | | // |
173 | 0 | void RBBISymbolTable::addEntry (const UnicodeString &key, RBBINode *val, UErrorCode &err) { |
174 | 0 | RBBISymbolTableEntry *e; |
175 | | /* test for buffer overflows */ |
176 | 0 | if (U_FAILURE(err)) { |
177 | 0 | return; |
178 | 0 | } |
179 | 0 | e = static_cast<RBBISymbolTableEntry*>(uhash_get(fHashTable, &key)); |
180 | 0 | if (e != nullptr) { |
181 | 0 | err = U_BRK_VARIABLE_REDFINITION; |
182 | 0 | return; |
183 | 0 | } |
184 | | |
185 | 0 | e = new RBBISymbolTableEntry; |
186 | 0 | if (e == nullptr) { |
187 | 0 | err = U_MEMORY_ALLOCATION_ERROR; |
188 | 0 | return; |
189 | 0 | } |
190 | 0 | e->key = key; |
191 | 0 | e->val = val; |
192 | 0 | uhash_put( fHashTable, &e->key, e, &err); |
193 | 0 | } |
194 | | |
195 | | |
196 | 0 | RBBISymbolTableEntry::RBBISymbolTableEntry() : UMemory(), key(), val(nullptr) {} |
197 | | |
198 | 0 | RBBISymbolTableEntry::~RBBISymbolTableEntry() { |
199 | | // The "val" of a symbol table entry is a variable reference node. |
200 | | // The l. child of the val is the rhs expression from the assignment. |
201 | | // Unlike other node types, children of variable reference nodes are not |
202 | | // automatically recursively deleted. We do it manually here. |
203 | 0 | delete val->fLeftChild; |
204 | 0 | val->fLeftChild = nullptr; |
205 | |
|
206 | 0 | delete val; |
207 | | |
208 | | // Note: the key UnicodeString is destructed by virtue of being in the object by value. |
209 | 0 | } |
210 | | |
211 | | |
212 | | // |
213 | | // RBBISymbolTable::print Debugging function, dump out the symbol table contents. |
214 | | // |
215 | | #ifdef RBBI_DEBUG |
216 | | void RBBISymbolTable::rbbiSymtablePrint() const { |
217 | | RBBIDebugPrintf("Variable Definitions Symbol Table\n" |
218 | | "Name Node serial String Val\n" |
219 | | "-------------------------------------------------------------------\n"); |
220 | | |
221 | | int32_t pos = UHASH_FIRST; |
222 | | const UHashElement *e = nullptr; |
223 | | for (;;) { |
224 | | e = uhash_nextElement(fHashTable, &pos); |
225 | | if (e == nullptr ) { |
226 | | break; |
227 | | } |
228 | | RBBISymbolTableEntry *s = (RBBISymbolTableEntry *)e->value.pointer; |
229 | | |
230 | | RBBIDebugPrintf("%-19s %8p %7d ", CStr(s->key)(), (void *)s->val, s->val->fSerialNum); |
231 | | RBBIDebugPrintf(" %s\n", CStr(s->val->fLeftChild->fText)()); |
232 | | } |
233 | | |
234 | | RBBIDebugPrintf("\nParsed Variable Definitions\n"); |
235 | | pos = -1; |
236 | | for (;;) { |
237 | | e = uhash_nextElement(fHashTable, &pos); |
238 | | if (e == nullptr ) { |
239 | | break; |
240 | | } |
241 | | RBBISymbolTableEntry *s = (RBBISymbolTableEntry *)e->value.pointer; |
242 | | RBBIDebugPrintf("%s\n", CStr(s->key)()); |
243 | | RBBINode::printTree(s->val, true); |
244 | | RBBINode::printTree(s->val->fLeftChild, false); |
245 | | RBBIDebugPrintf("\n"); |
246 | | } |
247 | | } |
248 | | #endif |
249 | | |
250 | | |
251 | | |
252 | | |
253 | | |
254 | | U_NAMESPACE_END |
255 | | |
256 | | #endif /* #if !UCONFIG_NO_BREAK_ITERATION */ |