xref: /aosp_15_r20/external/icu/libicu/cts_headers/unicode/messageformat2.h (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 #ifndef MESSAGEFORMAT2_H
7 #define MESSAGEFORMAT2_H
8 
9 #if U_SHOW_CPLUSPLUS_API
10 
11 #if !UCONFIG_NO_FORMATTING
12 
13 #if !UCONFIG_NO_MF2
14 
15 /**
16  * \file
17  * \brief C++ API: Formats messages using the draft MessageFormat 2.0.
18  */
19 
20 #include "unicode/messageformat2_arguments.h"
21 #include "unicode/messageformat2_data_model.h"
22 #include "unicode/messageformat2_function_registry.h"
23 #include "unicode/unistr.h"
24 
25 #ifndef U_HIDE_DEPRECATED_API
26 
27 U_NAMESPACE_BEGIN
28 
29 namespace message2 {
30 
31     class Environment;
32     class MessageContext;
33     class ResolvedSelector;
34     class StaticErrors;
35 
36     /**
37      * <p>MessageFormatter is a Technical Preview API implementing MessageFormat 2.0.
38      *
39      * <p>See <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md">the
40      * description of the syntax with examples and use cases</a> and the corresponding
41      * <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf">ABNF</a> grammar.</p>
42      *
43      * The MessageFormatter class is mutable and movable. It is not copyable.
44      * (It is mutable because if it has a custom function registry, the registry may include
45      * `FormatterFactory` objects implementing custom formatters, which are allowed to contain
46      * mutable state.)
47      *
48      * @internal ICU 75 technology preview
49      * @deprecated This API is for technology preview only.
50      */
51     class U_I18N_API MessageFormatter : public UObject {
52         // Note: This class does not currently inherit from the existing
53         // `Format` class.
54     public:
55         /**
56          * Move assignment operator:
57          * The source MessageFormatter will be left in a valid but undefined state.
58          *
59          * @internal ICU 75 technology preview
60          * @deprecated This API is for technology preview only.
61          */
62         MessageFormatter& operator=(MessageFormatter&&) noexcept;
63         /**
64          * Destructor.
65          *
66          * @internal ICU 75 technology preview
67          * @deprecated This API is for technology preview only.
68          */
69         virtual ~MessageFormatter();
70 
71         /**
72          * Formats the message to a string, using the data model that was previously set or parsed,
73          * and the given `arguments` object.
74          *
75          * @param arguments Reference to message arguments
76          * @param status    Input/output error code used to indicate syntax errors, data model
77          *                  errors, resolution errors, formatting errors, selection errors, as well
78          *                  as other errors (such as memory allocation failures). Partial output
79          *                  is still provided in the presence of most error types.
80          * @return          The string result of formatting the message with the given arguments.
81          *
82          * @internal ICU 75 technology preview
83          * @deprecated This API is for technology preview only.
84          */
85         UnicodeString formatToString(const MessageArguments& arguments, UErrorCode &status);
86 
87         /**
88          * Not yet implemented; formats the message to a `FormattedMessage` object,
89          * using the data model that was previously set or parsed,
90          * and the given `arguments` object.
91          *
92          * @param arguments Reference to message arguments
93          * @param status    Input/output error code used to indicate syntax errors, data model
94          *                  errors, resolution errors, formatting errors, selection errors, as well
95          *                  as other errors (such as memory allocation failures). Partial output
96          *                  is still provided in the presence of most error types.
97          * @return          The `FormattedMessage` representing the formatted message.
98          *
99          * @internal ICU 75 technology preview
100          * @deprecated This API is for technology preview only.
101          */
format(const MessageArguments & arguments,UErrorCode & status)102         FormattedMessage format(const MessageArguments& arguments, UErrorCode &status) const {
103             (void) arguments;
104             if (U_SUCCESS(status)) {
105                 status = U_UNSUPPORTED_ERROR;
106             }
107             return FormattedMessage(status);
108         }
109 
110         /**
111          * Accesses the locale that this `MessageFormatter` object was created with.
112          *
113          * @return A reference to the locale.
114          *
115          * @internal ICU 75 technology preview
116          * @deprecated This API is for technology preview only.
117          */
getLocale()118         const Locale& getLocale() const { return locale; }
119 
120         /**
121          * Serializes the data model as a string in MessageFormat 2.0 syntax.
122          *
123          * @return result    A string representation of the data model.
124          *                   The string is a valid MessageFormat 2.0 message.
125          *
126          * @internal ICU 75 technology preview
127          * @deprecated This API is for technology preview only.
128          */
129         UnicodeString getPattern() const;
130 
131         /**
132          * Accesses the data model referred to by this
133          * `MessageFormatter` object.
134          *
135          * @return A reference to the data model.
136          *
137          * @internal ICU 75 technology preview
138          * @deprecated This API is for technology preview only.
139          */
140         const MFDataModel& getDataModel() const;
141 
142         /**
143          * The mutable Builder class allows each part of the MessageFormatter to be initialized
144          * separately; calling its `build()` method yields an immutable MessageFormatter.
145          *
146          * Not copyable or movable.
147          */
148         class U_I18N_API Builder : public UObject {
149         private:
150             friend class MessageFormatter;
151 
152             // The pattern to be parsed to generate the formatted message
153             UnicodeString pattern;
154             bool hasPattern = false;
155             bool hasDataModel = false;
156             // The data model to be used to generate the formatted message
157             // Initialized either by `setDataModel()`, or by the parser
158             // through a call to `setPattern()`
159             MFDataModel dataModel;
160             // Normalized representation of the pattern;
161             // ignored if `setPattern()` wasn't called
162             UnicodeString normalizedInput;
163             // Errors (internal representation of parse errors)
164             // Ignored if `setPattern()` wasn't called
165             StaticErrors* errors;
166             Locale locale;
167             // Not owned
168             const MFFunctionRegistry* customMFFunctionRegistry;
169 
170         public:
171             /**
172              * Sets the locale to use for formatting.
173              *
174              * @param locale The desired locale.
175              * @return       A reference to the builder.
176              *
177              * @internal ICU 75 technology preview
178              * @deprecated This API is for technology preview only.
179              */
180             Builder& setLocale(const Locale& locale);
181             /**
182              * Sets the pattern (contents of the message) and parses it
183              * into a data model. If a data model was
184              * previously set, it is removed.
185              *
186              * @param pattern A string in MessageFormat 2.0 syntax.
187              * @param parseError Struct to receive information on the position
188              *                   of an error within the pattern.
189              * @param status    Input/output error code. If the
190              *                  pattern cannot be parsed, set to failure code.
191              * @return       A reference to the builder.
192              *
193              * @internal ICU 75 technology preview
194              * @deprecated This API is for technology preview only.
195              */
196             Builder& setPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status);
197             /**
198              * Sets a custom function registry.
199              *
200              * @param functionRegistry Reference to the function registry to use.
201              *        `functionRegistry` is not copied,
202              *        and the caller must ensure its lifetime contains
203              *        the lifetime of the `MessageFormatter` object built by this
204              *        builder.
205              * @return       A reference to the builder.
206              *
207              * @internal ICU 75 technology preview
208              * @deprecated This API is for technology preview only.
209              */
210             Builder& setFunctionRegistry(const MFFunctionRegistry& functionRegistry);
211             /**
212              * Sets a data model. If a pattern was previously set, it is removed.
213              *
214              * @param dataModel Data model to format. Passed by move.
215              * @return       A reference to the builder.
216              *
217              * @internal ICU 75 technology preview
218              * @deprecated This API is for technology preview only.
219              */
220             Builder& setDataModel(MFDataModel&& dataModel);
221             /**
222              * Constructs a new immutable MessageFormatter using the pattern or data model
223              * that was previously set, and the locale (if it was previously set)
224              * or default locale (otherwise).
225              *
226              * The builder object (`this`) can still be used after calling `build()`.
227              *
228              * @param status    Input/output error code.  If neither the pattern
229              *                  nor the data model is set, set to failure code.
230              * @return          The new MessageFormatter object
231              *
232              * @internal ICU 75 technology preview
233              * @deprecated This API is for technology preview only.
234              */
235             MessageFormatter build(UErrorCode& status) const;
236             /**
237              * Default constructor.
238              * Returns a Builder with the default locale and with no
239              * data model or pattern set. Either `setPattern()`
240              * or `setDataModel()` has to be called before calling `build()`.
241              *
242              * @param status    Input/output error code.
243              *
244              * @internal ICU 75 technology preview
245              * @deprecated This API is for technology preview only.
246              */
247             Builder(UErrorCode& status);
248             /**
249              * Destructor.
250              *
251              * @internal ICU 75 technology preview
252              * @deprecated This API is for technology preview only.
253              */
254             virtual ~Builder();
255         }; // class MessageFormatter::Builder
256 
257         // TODO: Shouldn't be public; only used for testing
258         /**
259          * Returns a string consisting of the input with optional spaces removed.
260          *
261          * @return        A normalized string representation of the input
262          *
263          * @internal ICU 75 technology preview
264          * @deprecated This API is for technology preview only.
265          */
getNormalizedPattern()266         const UnicodeString& getNormalizedPattern() const { return normalizedInput; }
267 
268     private:
269         friend class Builder;
270         friend class MessageContext;
271 
272         MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &status);
273 
274         MessageFormatter() = delete; // default constructor not implemented
275 
276         // Do not define default assignment operator
277         const MessageFormatter &operator=(const MessageFormatter &) = delete;
278 
279         ResolvedSelector resolveVariables(const Environment& env, const data_model::Operand&, MessageContext&, UErrorCode &) const;
280         ResolvedSelector resolveVariables(const Environment& env, const data_model::Expression&, MessageContext&, UErrorCode &) const;
281 
282         // Selection methods
283 
284         // Takes a vector of FormattedPlaceholders
285         void resolveSelectors(MessageContext&, const Environment& env, UErrorCode&, UVector&) const;
286         // Takes a vector of vectors of strings (input) and a vector of PrioritizedVariants (output)
287         void filterVariants(const UVector&, UVector&, UErrorCode&) const;
288         // Takes a vector of vectors of strings (input) and a vector of PrioritizedVariants (input/output)
289         void sortVariants(const UVector&, UVector&, UErrorCode&) const;
290         // Takes a vector of strings (input) and a vector of strings (output)
291         void matchSelectorKeys(const UVector&, MessageContext&, ResolvedSelector&& rv, UVector&, UErrorCode&) const;
292         // Takes a vector of FormattedPlaceholders (input),
293         // and a vector of vectors of strings (output)
294         void resolvePreferences(MessageContext&, UVector&, UVector&, UErrorCode&) const;
295 
296         // Formatting methods
297         [[nodiscard]] FormattedPlaceholder formatLiteral(const data_model::Literal&) const;
298         void formatPattern(MessageContext&, const Environment&, const data_model::Pattern&, UErrorCode&, UnicodeString&) const;
299         // Formats a call to a formatting function
300         // Dispatches on argument type
301         [[nodiscard]] FormattedPlaceholder evalFormatterCall(FormattedPlaceholder&& argument,
302                                                        MessageContext& context,
303                                                        UErrorCode& status) const;
304         // Dispatches on function name
305         [[nodiscard]] FormattedPlaceholder evalFormatterCall(const FunctionName& functionName,
306                                                        FormattedPlaceholder&& argument,
307                                                        FunctionOptions&& options,
308                                                        MessageContext& context,
309                                                        UErrorCode& status) const;
310         // Formats an expression that appears as a selector
311         ResolvedSelector formatSelectorExpression(const Environment& env, const data_model::Expression&, MessageContext&, UErrorCode&) const;
312         // Formats an expression that appears in a pattern or as the definition of a local variable
313         [[nodiscard]] FormattedPlaceholder formatExpression(const Environment&, const data_model::Expression&, MessageContext&, UErrorCode&) const;
314         [[nodiscard]] FunctionOptions resolveOptions(const Environment& env, const OptionMap&, MessageContext&, UErrorCode&) const;
315         [[nodiscard]] FormattedPlaceholder formatOperand(const Environment&, const data_model::Operand&, MessageContext&, UErrorCode&) const;
316         [[nodiscard]] FormattedPlaceholder evalArgument(const data_model::VariableName&, MessageContext&, UErrorCode&) const;
317         void formatSelectors(MessageContext& context, const Environment& env, UErrorCode &status, UnicodeString& result) const;
318 
319         // Function registry methods
hasCustomMFFunctionRegistry()320         bool hasCustomMFFunctionRegistry() const {
321             return (customMFFunctionRegistry != nullptr);
322         }
323 
324         // Precondition: custom function registry exists
325         // Note: this is non-const because the values in the MFFunctionRegistry are mutable
326         // (a FormatterFactory can have mutable state)
327         const MFFunctionRegistry& getCustomMFFunctionRegistry() const;
328 
329         bool isCustomFormatter(const FunctionName&) const;
330         FormatterFactory* lookupFormatterFactory(const FunctionName&, UErrorCode& status) const;
331         bool isBuiltInSelector(const FunctionName&) const;
332         bool isBuiltInFormatter(const FunctionName&) const;
333         bool isCustomSelector(const FunctionName&) const;
334         const SelectorFactory* lookupSelectorFactory(MessageContext&, const FunctionName&, UErrorCode&) const;
isSelector(const FunctionName & fn)335         bool isSelector(const FunctionName& fn) const { return isBuiltInSelector(fn) || isCustomSelector(fn); }
isFormatter(const FunctionName & fn)336         bool isFormatter(const FunctionName& fn) const { return isBuiltInFormatter(fn) || isCustomFormatter(fn); }
337         const Formatter* lookupFormatter(const FunctionName&, UErrorCode&) const;
338 
339         Selector* getSelector(MessageContext&, const FunctionName&, UErrorCode&) const;
340         Formatter* getFormatter(const FunctionName&, UErrorCode&) const;
341         bool getDefaultFormatterNameByType(const UnicodeString&, FunctionName&) const;
342 
343         // Checking for resolution errors
344         void checkDeclarations(MessageContext&, Environment*&, UErrorCode&) const;
345         void check(MessageContext&, const Environment&, const data_model::Expression&, UErrorCode&) const;
346         void check(MessageContext&, const Environment&, const data_model::Operand&, UErrorCode&) const;
347         void check(MessageContext&, const Environment&, const OptionMap&, UErrorCode&) const;
348 
349         void initErrors(UErrorCode&);
350         void clearErrors() const;
351         void cleanup() noexcept;
352 
353         // The locale this MessageFormatter was created with
354         /* const */ Locale locale;
355 
356         // Registry for built-in functions
357         MFFunctionRegistry standardMFFunctionRegistry;
358         // Registry for custom functions; may be null if no custom registry supplied
359         // Note: this is *not* owned by the MessageFormatter object
360         // The reason for this choice is to have a non-destructive MessageFormatter::Builder,
361         // while also not requiring the function registry to be deeply-copyable. Making the
362         // function registry copyable would impose a requirement on any implementations
363         // of the FormatterFactory and SelectorFactory interfaces to implement a custom
364         // clone() method, which is necessary to avoid sharing between copies of the
365         // function registry (and thus double-frees)
366         // Not deeply immutable (the values in the function registry are mutable,
367         // as a FormatterFactory can have mutable state
368         const MFFunctionRegistry* customMFFunctionRegistry;
369 
370         // Data model, representing the parsed message
371         MFDataModel dataModel;
372 
373         // Normalized version of the input string (optional whitespace removed)
374         UnicodeString normalizedInput;
375 
376         // Errors -- only used while parsing and checking for data model errors; then
377         // the MessageContext keeps track of errors
378         // Must be a raw pointer to avoid including the internal header file
379         // defining StaticErrors
380         // Owned by `this`
381         StaticErrors* errors;
382 
383     }; // class MessageFormatter
384 
385 } // namespace message2
386 
387 U_NAMESPACE_END
388 
389 #endif // U_HIDE_DEPRECATED_API
390 
391 #endif /* #if !UCONFIG_NO_MF2 */
392 
393 #endif /* #if !UCONFIG_NO_FORMATTING */
394 
395 #endif /* U_SHOW_CPLUSPLUS_API */
396 
397 #endif // MESSAGEFORMAT2_H
398 
399 // eof
400