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