• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2024 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 #if !UCONFIG_NO_MF2
9 
10 #include "unicode/messageformat2.h"
11 #include "messageformat2_allocation.h"
12 #include "messageformat2_checker.h"
13 #include "messageformat2_errors.h"
14 #include "messageformat2_evaluation.h"
15 #include "messageformat2_function_registry_internal.h"
16 #include "messageformat2_macros.h"
17 #include "messageformat2_parser.h"
18 #include "messageformat2_serializer.h"
19 #include "uvector.h" // U_ASSERT
20 
21 U_NAMESPACE_BEGIN
22 
23 namespace message2 {
24 
25     // MessageFormatter::Builder
26 
27     // -------------------------------------
28     // Creates a MessageFormat instance based on the pattern.
29 
clearState()30     void MessageFormatter::Builder::clearState() {
31         normalizedInput.remove();
32         delete errors;
33         errors = nullptr;
34     }
35 
setPattern(const UnicodeString & pat,UParseError & parseError,UErrorCode & errorCode)36     MessageFormatter::Builder& MessageFormatter::Builder::setPattern(const UnicodeString& pat,
37                                                                      UParseError& parseError,
38                                                                      UErrorCode& errorCode) {
39         clearState();
40         // Create errors
41         errors = create<StaticErrors>(StaticErrors(errorCode), errorCode);
42         THIS_ON_ERROR(errorCode);
43 
44         // Parse the pattern
45         MFDataModel::Builder tree(errorCode);
46         Parser(pat, tree, *errors, normalizedInput).parse(parseError, errorCode);
47 
48         // Fail on syntax errors
49         if (errors->hasSyntaxError()) {
50             errors->checkErrors(errorCode);
51             // Check that the checkErrors() method set the error code
52             U_ASSERT(U_FAILURE(errorCode));
53         }
54 
55         // Build the data model based on what was parsed
56         dataModel = tree.build(errorCode);
57         hasDataModel = true;
58         hasPattern = true;
59         pattern = pat;
60 
61         return *this;
62     }
63 
64     // Precondition: `reg` is non-null
65     // Does not adopt `reg`
setFunctionRegistry(const MFFunctionRegistry & reg)66     MessageFormatter::Builder& MessageFormatter::Builder::setFunctionRegistry(const MFFunctionRegistry& reg) {
67         customMFFunctionRegistry = &reg;
68         return *this;
69     }
70 
setLocale(const Locale & loc)71     MessageFormatter::Builder& MessageFormatter::Builder::setLocale(const Locale& loc) {
72         locale = loc;
73         return *this;
74     }
75 
setDataModel(MFDataModel && newDataModel)76     MessageFormatter::Builder& MessageFormatter::Builder::setDataModel(MFDataModel&& newDataModel) {
77         clearState();
78         hasPattern = false;
79         hasDataModel = true;
80         dataModel = std::move(newDataModel);
81 
82         return *this;
83     }
84 
85     MessageFormatter::Builder&
setErrorHandlingBehavior(MessageFormatter::UMFErrorHandlingBehavior type)86         MessageFormatter::Builder::setErrorHandlingBehavior(
87            MessageFormatter::UMFErrorHandlingBehavior type) {
88                signalErrors = type == U_MF_STRICT;
89                return *this;
90     }
91 
92     /*
93       This build() method is non-destructive, which entails the risk that
94       its borrowed MFFunctionRegistry and (if the setDataModel() method was called)
95       MFDataModel pointers could become invalidated.
96     */
build(UErrorCode & errorCode) const97     MessageFormatter MessageFormatter::Builder::build(UErrorCode& errorCode) const {
98         return MessageFormatter(*this, errorCode);
99     }
100 
Builder(UErrorCode & errorCode)101     MessageFormatter::Builder::Builder(UErrorCode& errorCode) : locale(Locale::getDefault()), customMFFunctionRegistry(nullptr) {
102         // Initialize errors
103         errors = new StaticErrors(errorCode);
104         CHECK_ERROR(errorCode);
105         if (errors == nullptr) {
106             errorCode = U_MEMORY_ALLOCATION_ERROR;
107         }
108     }
109 
~Builder()110     MessageFormatter::Builder::~Builder() {
111         if (errors != nullptr) {
112             delete errors;
113             errors = nullptr;
114         }
115     }
116 
117     // MessageFormatter
118 
MessageFormatter(const MessageFormatter::Builder & builder,UErrorCode & success)119     MessageFormatter::MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &success) : locale(builder.locale), customMFFunctionRegistry(builder.customMFFunctionRegistry) {
120         CHECK_ERROR(success);
121 
122         // Set up the standard function registry
123         MFFunctionRegistry::Builder standardFunctionsBuilder(success);
124 
125         FormatterFactory* dateTime = StandardFunctions::DateTimeFactory::dateTime(success);
126         FormatterFactory* date = StandardFunctions::DateTimeFactory::date(success);
127         FormatterFactory* time = StandardFunctions::DateTimeFactory::time(success);
128         FormatterFactory* number = new StandardFunctions::NumberFactory();
129         FormatterFactory* integer = new StandardFunctions::IntegerFactory();
130         standardFunctionsBuilder.adoptFormatter(FunctionName(UnicodeString("datetime")), dateTime, success)
131             .adoptFormatter(FunctionName(UnicodeString("date")), date, success)
132             .adoptFormatter(FunctionName(UnicodeString("time")), time, success)
133             .adoptFormatter(FunctionName(UnicodeString("number")), number, success)
134             .adoptFormatter(FunctionName(UnicodeString("integer")), integer, success)
135             .adoptSelector(FunctionName(UnicodeString("number")), new StandardFunctions::PluralFactory(UPLURAL_TYPE_CARDINAL), success)
136             .adoptSelector(FunctionName(UnicodeString("integer")), new StandardFunctions::PluralFactory(StandardFunctions::PluralFactory::integer()), success)
137             .adoptSelector(FunctionName(UnicodeString("string")), new StandardFunctions::TextFactory(), success);
138         CHECK_ERROR(success);
139         standardMFFunctionRegistry = standardFunctionsBuilder.build();
140         CHECK_ERROR(success);
141         standardMFFunctionRegistry.checkStandard();
142 
143         normalizedInput = builder.normalizedInput;
144         signalErrors = builder.signalErrors;
145 
146         // Build data model
147         // First, check that there is a data model
148         // (which might have been set by setDataModel(), or to
149         // the data model parsed from the pattern by setPattern())
150 
151         if (!builder.hasDataModel) {
152             success = U_INVALID_STATE_ERROR;
153             return;
154         }
155 
156         dataModel = builder.dataModel;
157         if (builder.errors != nullptr) {
158             errors = new StaticErrors(*builder.errors, success);
159         } else {
160             // Initialize errors
161             LocalPointer<StaticErrors> errorsNew(new StaticErrors(success));
162             CHECK_ERROR(success);
163             errors = errorsNew.orphan();
164         }
165 
166         // Note: we currently evaluate variables lazily,
167         // without memoization. This call is still necessary
168         // to check out-of-scope uses of local variables in
169         // right-hand sides (unresolved variable errors can
170         // only be checked when arguments are known)
171 
172         // Check for resolution errors
173         Checker(dataModel, *errors).check(success);
174     }
175 
cleanup()176     void MessageFormatter::cleanup() noexcept {
177         if (errors != nullptr) {
178             delete errors;
179             errors = nullptr;
180         }
181     }
182 
operator =(MessageFormatter && other)183     MessageFormatter& MessageFormatter::operator=(MessageFormatter&& other) noexcept {
184         cleanup();
185 
186         locale = std::move(other.locale);
187         standardMFFunctionRegistry = std::move(other.standardMFFunctionRegistry);
188         customMFFunctionRegistry = other.customMFFunctionRegistry;
189         dataModel = std::move(other.dataModel);
190         normalizedInput = std::move(other.normalizedInput);
191         signalErrors = other.signalErrors;
192         errors = other.errors;
193         other.errors = nullptr;
194         return *this;
195     }
196 
getDataModel() const197     const MFDataModel& MessageFormatter::getDataModel() const { return dataModel; }
198 
getPattern() const199     UnicodeString MessageFormatter::getPattern() const {
200         // Converts the current data model back to a string
201         UnicodeString result;
202         Serializer serializer(getDataModel(), result);
203         serializer.serialize();
204         return result;
205     }
206 
207     // Precondition: custom function registry exists
getCustomMFFunctionRegistry() const208     const MFFunctionRegistry& MessageFormatter::getCustomMFFunctionRegistry() const {
209         U_ASSERT(hasCustomMFFunctionRegistry());
210         return *customMFFunctionRegistry;
211     }
212 
~MessageFormatter()213     MessageFormatter::~MessageFormatter() {
214         cleanup();
215     }
216 
217     // Selector and formatter lookup
218     // -----------------------------
219 
220     // Postcondition: selector != nullptr || U_FAILURE(status)
getSelector(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const221     Selector* MessageFormatter::getSelector(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const {
222         NULL_ON_ERROR(status);
223         U_ASSERT(isSelector(functionName));
224 
225         const SelectorFactory* selectorFactory = lookupSelectorFactory(context, functionName, status);
226         NULL_ON_ERROR(status);
227         if (selectorFactory == nullptr) {
228             status = U_MEMORY_ALLOCATION_ERROR;
229             return nullptr;
230         }
231         // Create a specific instance of the selector
232         auto result = selectorFactory->createSelector(getLocale(), status);
233         NULL_ON_ERROR(status);
234         return result;
235     }
236 
237     // Returns an owned pointer
getFormatter(const FunctionName & functionName,UErrorCode & status) const238     Formatter* MessageFormatter::getFormatter(const FunctionName& functionName, UErrorCode& status) const {
239         NULL_ON_ERROR(status);
240 
241         // Create the formatter
242 
243         // First, look up the formatter factory for this function
244         FormatterFactory* formatterFactory = lookupFormatterFactory(functionName, status);
245         NULL_ON_ERROR(status);
246 
247         U_ASSERT(formatterFactory != nullptr);
248 
249         // Create a specific instance of the formatter
250         Formatter* formatter = formatterFactory->createFormatter(locale, status);
251         NULL_ON_ERROR(status);
252         if (formatter == nullptr) {
253             status = U_MEMORY_ALLOCATION_ERROR;
254             return nullptr;
255         }
256         return formatter;
257     }
258 
getDefaultFormatterNameByType(const UnicodeString & type,FunctionName & name) const259     bool MessageFormatter::getDefaultFormatterNameByType(const UnicodeString& type, FunctionName& name) const {
260         U_ASSERT(hasCustomMFFunctionRegistry());
261         const MFFunctionRegistry& reg = getCustomMFFunctionRegistry();
262         return reg.getDefaultFormatterNameByType(type, name);
263     }
264 
265     // ---------------------------------------------------
266     // Function registry
267 
isBuiltInSelector(const FunctionName & functionName) const268     bool MessageFormatter::isBuiltInSelector(const FunctionName& functionName) const {
269         return standardMFFunctionRegistry.hasSelector(functionName);
270     }
271 
isBuiltInFormatter(const FunctionName & functionName) const272     bool MessageFormatter::isBuiltInFormatter(const FunctionName& functionName) const {
273         return standardMFFunctionRegistry.hasFormatter(functionName);
274     }
275 
276     // https://github.com/unicode-org/message-format-wg/issues/409
277     // Unknown function = unknown function error
278     // Formatter used as selector  = selector error
279     // Selector used as formatter = formatting error
lookupSelectorFactory(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const280     const SelectorFactory* MessageFormatter::lookupSelectorFactory(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const {
281         DynamicErrors& err = context.getErrors();
282 
283         if (isBuiltInSelector(functionName)) {
284             return standardMFFunctionRegistry.getSelector(functionName);
285         }
286         if (isBuiltInFormatter(functionName)) {
287             err.setSelectorError(functionName, status);
288             return nullptr;
289         }
290         if (hasCustomMFFunctionRegistry()) {
291             const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry();
292             const SelectorFactory* selectorFactory = customMFFunctionRegistry.getSelector(functionName);
293             if (selectorFactory != nullptr) {
294                 return selectorFactory;
295             }
296             if (customMFFunctionRegistry.getFormatter(functionName) != nullptr) {
297                 err.setSelectorError(functionName, status);
298                 return nullptr;
299             }
300         }
301         // Either there is no custom function registry and the function
302         // isn't built-in, or the function doesn't exist in either the built-in
303         // or custom registry.
304         // Unknown function error
305         err.setUnknownFunction(functionName, status);
306         return nullptr;
307     }
308 
lookupFormatterFactory(const FunctionName & functionName,UErrorCode & status) const309     FormatterFactory* MessageFormatter::lookupFormatterFactory(const FunctionName& functionName,
310                                                                UErrorCode& status) const {
311         NULL_ON_ERROR(status);
312 
313         if (isBuiltInFormatter(functionName)) {
314             return standardMFFunctionRegistry.getFormatter(functionName);
315         }
316         if (isBuiltInSelector(functionName)) {
317             status = U_MF_FORMATTING_ERROR;
318             return nullptr;
319         }
320         if (hasCustomMFFunctionRegistry()) {
321             const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry();
322             FormatterFactory* formatterFactory = customMFFunctionRegistry.getFormatter(functionName);
323             if (formatterFactory != nullptr) {
324                 return formatterFactory;
325             }
326             if (customMFFunctionRegistry.getSelector(functionName) != nullptr) {
327                 status = U_MF_FORMATTING_ERROR;
328                 return nullptr;
329             }
330         }
331         // Either there is no custom function registry and the function
332         // isn't built-in, or the function doesn't exist in either the built-in
333         // or custom registry.
334         // Unknown function error
335         status = U_MF_UNKNOWN_FUNCTION_ERROR;
336         return nullptr;
337     }
338 
isCustomFormatter(const FunctionName & fn) const339     bool MessageFormatter::isCustomFormatter(const FunctionName& fn) const {
340         return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getFormatter(fn) != nullptr;
341     }
342 
343 
isCustomSelector(const FunctionName & fn) const344     bool MessageFormatter::isCustomSelector(const FunctionName& fn) const {
345         return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getSelector(fn) != nullptr;
346     }
347 
348 } // namespace message2
349 
350 U_NAMESPACE_END
351 
352 #endif /* #if !UCONFIG_NO_MF2 */
353 
354 #endif /* #if !UCONFIG_NO_FORMATTING */
355