xref: /aosp_15_r20/external/icu/icu4c/source/i18n/messageformat2_formatter.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
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 
setPattern(const UnicodeString & pat,UParseError & parseError,UErrorCode & errorCode)30     MessageFormatter::Builder& MessageFormatter::Builder::setPattern(const UnicodeString& pat, UParseError& parseError, UErrorCode& errorCode) {
31         normalizedInput.remove();
32         // Parse the pattern
33         MFDataModel::Builder tree(errorCode);
34         Parser(pat, tree, *errors, normalizedInput).parse(parseError, errorCode);
35 
36         // Build the data model based on what was parsed
37         dataModel = tree.build(errorCode);
38         hasDataModel = true;
39         hasPattern = true;
40         pattern = pat;
41 
42         return *this;
43     }
44 
45     // Precondition: `reg` is non-null
46     // Does not adopt `reg`
setFunctionRegistry(const MFFunctionRegistry & reg)47     MessageFormatter::Builder& MessageFormatter::Builder::setFunctionRegistry(const MFFunctionRegistry& reg) {
48         customMFFunctionRegistry = ®
49         return *this;
50     }
51 
setLocale(const Locale & loc)52     MessageFormatter::Builder& MessageFormatter::Builder::setLocale(const Locale& loc) {
53         locale = loc;
54         return *this;
55     }
56 
setDataModel(MFDataModel && newDataModel)57     MessageFormatter::Builder& MessageFormatter::Builder::setDataModel(MFDataModel&& newDataModel) {
58         normalizedInput.remove();
59         delete errors;
60         errors = nullptr;
61         hasPattern = false;
62         hasDataModel = true;
63         dataModel = std::move(newDataModel);
64 
65         return *this;
66     }
67 
68     /*
69       This build() method is non-destructive, which entails the risk that
70       its borrowed MFFunctionRegistry and (if the setDataModel() method was called)
71       MFDataModel pointers could become invalidated.
72     */
build(UErrorCode & errorCode) const73     MessageFormatter MessageFormatter::Builder::build(UErrorCode& errorCode) const {
74         return MessageFormatter(*this, errorCode);
75     }
76 
Builder(UErrorCode & errorCode)77     MessageFormatter::Builder::Builder(UErrorCode& errorCode) : locale(Locale::getDefault()), customMFFunctionRegistry(nullptr) {
78         // Initialize errors
79         errors = new StaticErrors(errorCode);
80         CHECK_ERROR(errorCode);
81         if (errors == nullptr) {
82             errorCode = U_MEMORY_ALLOCATION_ERROR;
83         }
84     }
85 
~Builder()86     MessageFormatter::Builder::~Builder() {
87         if (errors != nullptr) {
88             delete errors;
89         }
90     }
91 
92     // MessageFormatter
93 
MessageFormatter(const MessageFormatter::Builder & builder,UErrorCode & success)94     MessageFormatter::MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &success) : locale(builder.locale), customMFFunctionRegistry(builder.customMFFunctionRegistry) {
95         CHECK_ERROR(success);
96 
97         // Set up the standard function registry
98         MFFunctionRegistry::Builder standardFunctionsBuilder(success);
99 
100         FormatterFactory* dateTime = StandardFunctions::DateTimeFactory::dateTime(success);
101         FormatterFactory* date = StandardFunctions::DateTimeFactory::date(success);
102         FormatterFactory* time = StandardFunctions::DateTimeFactory::time(success);
103         FormatterFactory* number = new StandardFunctions::NumberFactory();
104         FormatterFactory* integer = new StandardFunctions::IntegerFactory();
105         standardFunctionsBuilder.adoptFormatter(FunctionName(UnicodeString("datetime")), dateTime, success)
106             .adoptFormatter(FunctionName(UnicodeString("date")), date, success)
107             .adoptFormatter(FunctionName(UnicodeString("time")), time, success)
108             .adoptFormatter(FunctionName(UnicodeString("number")), number, success)
109             .adoptFormatter(FunctionName(UnicodeString("integer")), integer, success)
110             .adoptSelector(FunctionName(UnicodeString("number")), new StandardFunctions::PluralFactory(UPLURAL_TYPE_CARDINAL), success)
111             .adoptSelector(FunctionName(UnicodeString("integer")), new StandardFunctions::PluralFactory(StandardFunctions::PluralFactory::integer()), success)
112             .adoptSelector(FunctionName(UnicodeString("string")), new StandardFunctions::TextFactory(), success);
113         CHECK_ERROR(success);
114         standardMFFunctionRegistry = standardFunctionsBuilder.build();
115         CHECK_ERROR(success);
116         standardMFFunctionRegistry.checkStandard();
117 
118         normalizedInput = builder.normalizedInput;
119 
120         // Build data model
121         // First, check that there is a data model
122         // (which might have been set by setDataModel(), or to
123         // the data model parsed from the pattern by setPattern())
124 
125         if (!builder.hasDataModel) {
126             success = U_INVALID_STATE_ERROR;
127             return;
128         }
129 
130         dataModel = builder.dataModel;
131         if (builder.errors != nullptr) {
132             errors = new StaticErrors(*builder.errors, success);
133         } else {
134             // Initialize errors
135             LocalPointer<StaticErrors> errorsNew(new StaticErrors(success));
136             CHECK_ERROR(success);
137             errors = errorsNew.orphan();
138         }
139 
140         // Note: we currently evaluate variables lazily,
141         // without memoization. This call is still necessary
142         // to check out-of-scope uses of local variables in
143         // right-hand sides (unresolved variable errors can
144         // only be checked when arguments are known)
145 
146         // Check for resolution errors
147         Checker(dataModel, *errors).check(success);
148     }
149 
cleanup()150     void MessageFormatter::cleanup() noexcept {
151         if (errors != nullptr) {
152             delete errors;
153         }
154     }
155 
operator =(MessageFormatter && other)156     MessageFormatter& MessageFormatter::operator=(MessageFormatter&& other) noexcept {
157         cleanup();
158 
159         locale = std::move(other.locale);
160         standardMFFunctionRegistry = std::move(other.standardMFFunctionRegistry);
161         customMFFunctionRegistry = other.customMFFunctionRegistry;
162         dataModel = std::move(other.dataModel);
163         normalizedInput = std::move(other.normalizedInput);
164         errors = other.errors;
165         other.errors = nullptr;
166         return *this;
167     }
168 
getDataModel() const169     const MFDataModel& MessageFormatter::getDataModel() const { return dataModel; }
170 
getPattern() const171     UnicodeString MessageFormatter::getPattern() const {
172         // Converts the current data model back to a string
173         UnicodeString result;
174         Serializer serializer(getDataModel(), result);
175         serializer.serialize();
176         return result;
177     }
178 
179     // Precondition: custom function registry exists
getCustomMFFunctionRegistry() const180     const MFFunctionRegistry& MessageFormatter::getCustomMFFunctionRegistry() const {
181         U_ASSERT(hasCustomMFFunctionRegistry());
182         return *customMFFunctionRegistry;
183     }
184 
~MessageFormatter()185     MessageFormatter::~MessageFormatter() {
186         cleanup();
187     }
188 
189     // Selector and formatter lookup
190     // -----------------------------
191 
192     // Postcondition: selector != nullptr || U_FAILURE(status)
getSelector(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const193     Selector* MessageFormatter::getSelector(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const {
194         NULL_ON_ERROR(status);
195         U_ASSERT(isSelector(functionName));
196 
197         const SelectorFactory* selectorFactory = lookupSelectorFactory(context, functionName, status);
198         NULL_ON_ERROR(status);
199         if (selectorFactory == nullptr) {
200             status = U_MEMORY_ALLOCATION_ERROR;
201             return nullptr;
202         }
203         // Create a specific instance of the selector
204         auto result = selectorFactory->createSelector(getLocale(), status);
205         NULL_ON_ERROR(status);
206         return result;
207     }
208 
209     // Returns an owned pointer
getFormatter(const FunctionName & functionName,UErrorCode & status) const210     Formatter* MessageFormatter::getFormatter(const FunctionName& functionName, UErrorCode& status) const {
211         NULL_ON_ERROR(status);
212 
213         // Create the formatter
214 
215         // First, look up the formatter factory for this function
216         FormatterFactory* formatterFactory = lookupFormatterFactory(functionName, status);
217         NULL_ON_ERROR(status);
218 
219         U_ASSERT(formatterFactory != nullptr);
220 
221         // Create a specific instance of the formatter
222         Formatter* formatter = formatterFactory->createFormatter(locale, status);
223         NULL_ON_ERROR(status);
224         if (formatter == nullptr) {
225             status = U_MEMORY_ALLOCATION_ERROR;
226             return nullptr;
227         }
228         return formatter;
229     }
230 
getDefaultFormatterNameByType(const UnicodeString & type,FunctionName & name) const231     bool MessageFormatter::getDefaultFormatterNameByType(const UnicodeString& type, FunctionName& name) const {
232         U_ASSERT(hasCustomMFFunctionRegistry());
233         const MFFunctionRegistry& reg = getCustomMFFunctionRegistry();
234         return reg.getDefaultFormatterNameByType(type, name);
235     }
236 
237     // ---------------------------------------------------
238     // Function registry
239 
isBuiltInSelector(const FunctionName & functionName) const240     bool MessageFormatter::isBuiltInSelector(const FunctionName& functionName) const {
241         return standardMFFunctionRegistry.hasSelector(functionName);
242     }
243 
isBuiltInFormatter(const FunctionName & functionName) const244     bool MessageFormatter::isBuiltInFormatter(const FunctionName& functionName) const {
245         return standardMFFunctionRegistry.hasFormatter(functionName);
246     }
247 
248     // https://github.com/unicode-org/message-format-wg/issues/409
249     // Unknown function = unknown function error
250     // Formatter used as selector  = selector error
251     // Selector used as formatter = formatting error
lookupSelectorFactory(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const252     const SelectorFactory* MessageFormatter::lookupSelectorFactory(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const {
253         DynamicErrors& err = context.getErrors();
254 
255         if (isBuiltInSelector(functionName)) {
256             return standardMFFunctionRegistry.getSelector(functionName);
257         }
258         if (isBuiltInFormatter(functionName)) {
259             err.setSelectorError(functionName, status);
260             return nullptr;
261         }
262         if (hasCustomMFFunctionRegistry()) {
263             const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry();
264             const SelectorFactory* selectorFactory = customMFFunctionRegistry.getSelector(functionName);
265             if (selectorFactory != nullptr) {
266                 return selectorFactory;
267             }
268             if (customMFFunctionRegistry.getFormatter(functionName) != nullptr) {
269                 err.setSelectorError(functionName, status);
270                 return nullptr;
271             }
272         }
273         // Either there is no custom function registry and the function
274         // isn't built-in, or the function doesn't exist in either the built-in
275         // or custom registry.
276         // Unknown function error
277         err.setUnknownFunction(functionName, status);
278         return nullptr;
279     }
280 
lookupFormatterFactory(const FunctionName & functionName,UErrorCode & status) const281     FormatterFactory* MessageFormatter::lookupFormatterFactory(const FunctionName& functionName,
282                                                                UErrorCode& status) const {
283         NULL_ON_ERROR(status);
284 
285         if (isBuiltInFormatter(functionName)) {
286             return standardMFFunctionRegistry.getFormatter(functionName);
287         }
288         if (isBuiltInSelector(functionName)) {
289             status = U_MF_FORMATTING_ERROR;
290             return nullptr;
291         }
292         if (hasCustomMFFunctionRegistry()) {
293             const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry();
294             FormatterFactory* formatterFactory = customMFFunctionRegistry.getFormatter(functionName);
295             if (formatterFactory != nullptr) {
296                 return formatterFactory;
297             }
298             if (customMFFunctionRegistry.getSelector(functionName) != nullptr) {
299                 status = U_MF_FORMATTING_ERROR;
300                 return nullptr;
301             }
302         }
303         // Either there is no custom function registry and the function
304         // isn't built-in, or the function doesn't exist in either the built-in
305         // or custom registry.
306         // Unknown function error
307         status = U_MF_UNKNOWN_FUNCTION_ERROR;
308         return nullptr;
309     }
310 
isCustomFormatter(const FunctionName & fn) const311     bool MessageFormatter::isCustomFormatter(const FunctionName& fn) const {
312         return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getFormatter(fn) != nullptr;
313     }
314 
315 
isCustomSelector(const FunctionName & fn) const316     bool MessageFormatter::isCustomSelector(const FunctionName& fn) const {
317         return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getSelector(fn) != nullptr;
318     }
319 
320 } // namespace message2
321 
322 U_NAMESPACE_END
323 
324 #endif /* #if !UCONFIG_NO_MF2 */
325 
326 #endif /* #if !UCONFIG_NO_FORMATTING */
327