xref: /aosp_15_r20/external/icu/libicu/cts_headers/messageformat2_evaluation.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 U_HIDE_DEPRECATED_API
7 
8 #ifndef MESSAGEFORMAT2_EVALUATION_H
9 #define MESSAGEFORMAT2_EVALUATION_H
10 
11 #if U_SHOW_CPLUSPLUS_API
12 
13 /**
14  * \file
15  * \brief C++ API: Formats messages using the draft MessageFormat 2.0.
16  */
17 
18 #if !UCONFIG_NO_FORMATTING
19 
20 #if !UCONFIG_NO_MF2
21 
22 #include "unicode/messageformat2_arguments.h"
23 #include "unicode/messageformat2_data_model.h"
24 #include "unicode/messageformat2_function_registry.h"
25 #include "messageformat2_errors.h"
26 
27 // Auxiliary data structures used during formatting a message
28 
29 U_NAMESPACE_BEGIN
30 
31 namespace message2 {
32 
33     using namespace data_model;
34 
35     // PrioritizedVariant
36 
37     // For how this class is used, see the references to (integer, variant) tuples
38     // in https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection
39     class PrioritizedVariant : public UObject {
40     public:
41         PrioritizedVariant() = default;
42         PrioritizedVariant(PrioritizedVariant&&) = default;
43         PrioritizedVariant& operator=(PrioritizedVariant&&) noexcept = default;
44         UBool operator<(const PrioritizedVariant&) const;
45         int32_t priority;
46         /* const */ SelectorKeys keys;
47         /* const */ Pattern pat;
PrioritizedVariant(uint32_t p,const SelectorKeys & k,const Pattern & pattern)48         PrioritizedVariant(uint32_t p,
49                            const SelectorKeys& k,
50                            const Pattern& pattern) noexcept : priority(p), keys(k), pat(pattern) {}
51         virtual ~PrioritizedVariant();
52     }; // class PrioritizedVariant
53 
comparePrioritizedVariants(UElement left,UElement right)54     static inline int32_t comparePrioritizedVariants(UElement left, UElement right) {
55         const PrioritizedVariant& tuple1 = *(static_cast<const PrioritizedVariant*>(left.pointer));
56         const PrioritizedVariant& tuple2 = *(static_cast<const PrioritizedVariant*>(right.pointer));
57         if (tuple1 < tuple2) {
58             return -1;
59         }
60         if (tuple1.priority == tuple2.priority) {
61             return 0;
62         }
63         return 1;
64     }
65 
66     // Encapsulates a value to be scrutinized by a `match` with its resolved
67     // options and the name of the selector
68     class ResolvedSelector : public UObject {
69     public:
ResolvedSelector()70         ResolvedSelector() {}
71         ResolvedSelector(const FunctionName& fn,
72                          Selector* selector,
73                          FunctionOptions&& options,
74                          FormattedPlaceholder&& value);
75         // Used either for errors, or when selector isn't yet known
76         explicit ResolvedSelector(FormattedPlaceholder&& value);
hasSelector()77         bool hasSelector() const { return selector.isValid(); }
argument()78         const FormattedPlaceholder& argument() const { return value; }
takeArgument()79         FormattedPlaceholder&& takeArgument() { return std::move(value); }
getSelector()80         const Selector* getSelector() {
81             U_ASSERT(selector.isValid());
82             return selector.getAlias();
83         }
takeOptions()84         FunctionOptions&& takeOptions() {
85             return std::move(options);
86         }
getSelectorName()87         const FunctionName& getSelectorName() const { return selectorName; }
88         virtual ~ResolvedSelector();
89         ResolvedSelector& operator=(ResolvedSelector&&) noexcept;
90         ResolvedSelector(ResolvedSelector&&);
91     private:
92         FunctionName selectorName; // For error reporting
93         LocalPointer<Selector> selector;
94         FunctionOptions options;
95         FormattedPlaceholder value;
96     }; // class ResolvedSelector
97 
98     // Closures and environments
99     // -------------------------
100 
101     class Environment;
102 
103     // A closure represents the right-hand side of a variable
104     // declaration, along with an environment giving values
105     // to its free variables
106     class Closure : public UMemory {
107     public:
getExpr()108         const Expression& getExpr() const {
109             return expr;
110         }
getEnv()111         const Environment& getEnv() const {
112             return env;
113         }
Closure(const Expression & expression,const Environment & environment)114         Closure(const Expression& expression, const Environment& environment) : expr(expression), env(environment) {}
115         Closure(Closure&&) = default;
116 
117         virtual ~Closure();
118     private:
119 
120         // An unevaluated expression
121         const Expression& expr;
122         // The environment mapping names used in this
123         // expression to other expressions
124         const Environment& env;
125     };
126 
127     // An environment is represented as a linked chain of
128     // non-empty environments, terminating at an empty environment.
129     // It's searched using linear search.
130     class Environment : public UMemory {
131     public:
132         virtual bool has(const VariableName&) const = 0;
133         virtual const Closure& lookup(const VariableName&) const = 0;
134         static Environment* create(UErrorCode&);
135         static Environment* create(const VariableName&, Closure&&, Environment*, UErrorCode&);
136         virtual ~Environment();
137     };
138 
139     class NonEmptyEnvironment;
140     class EmptyEnvironment : public Environment {
141     public:
142         EmptyEnvironment() = default;
143         virtual ~EmptyEnvironment();
144 
145     private:
146         friend class Environment;
147 
148         bool has(const VariableName&) const override;
149         const Closure& lookup(const VariableName&) const override;
150         static EmptyEnvironment* create(UErrorCode&);
151         static NonEmptyEnvironment* create(const VariableName&, Closure&&, Environment*, UErrorCode&);
152     };
153 
154     class NonEmptyEnvironment : public Environment {
155     private:
156         friend class Environment;
157 
158         bool has(const VariableName&) const override;
159         const Closure& lookup(const VariableName&) const override;
160         static NonEmptyEnvironment* create(const VariableName&, Closure&&, const Environment*, UErrorCode&);
161         virtual ~NonEmptyEnvironment();
162     private:
163         friend class Environment;
164 
NonEmptyEnvironment(const VariableName & v,Closure && c,Environment * e)165         NonEmptyEnvironment(const VariableName& v, Closure&& c, Environment* e) : var(v), rhs(std::move(c)), parent(e) {}
166 
167         // Maps VariableName onto Closure*
168         // Chain of linked environments
169         VariableName var;
170         Closure rhs;
171         const LocalPointer<Environment> parent;
172     };
173 
174     // The context contains all the information needed to process
175     // an entire message: arguments, formatter cache, and error list
176 
177     class MessageContext : public UMemory {
178     public:
179         MessageContext(const MessageArguments&, const StaticErrors&, UErrorCode&);
180 
181         const Formattable* getGlobal(const VariableName&, UErrorCode&) const;
182 
183         // If any errors were set, update `status` accordingly
184         void checkErrors(UErrorCode& status) const;
getErrors()185         DynamicErrors& getErrors() { return errors; }
186 
187         virtual ~MessageContext();
188 
189     private:
190 
191         const MessageArguments& arguments; // External message arguments
192         // Errors accumulated during parsing/formatting
193         DynamicErrors errors;
194     }; // class MessageContext
195 
196 } // namespace message2
197 
198 U_NAMESPACE_END
199 
200 #endif /* #if !UCONFIG_NO_MF2 */
201 
202 #endif /* #if !UCONFIG_NO_FORMATTING */
203 
204 #endif /* U_SHOW_CPLUSPLUS_API */
205 
206 #endif // MESSAGEFORMAT2_EVALUATION_H
207 
208 #endif // U_HIDE_DEPRECATED_API
209 // eof
210