messageformat2_evaluation.h (8251B)
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 #if !UCONFIG_NO_NORMALIZATION 18 19 #if !UCONFIG_NO_FORMATTING 20 21 #if !UCONFIG_NO_MF2 22 23 #include "unicode/messageformat2_arguments.h" 24 #include "unicode/messageformat2_data_model.h" 25 #include "unicode/messageformat2_function_registry.h" 26 #include "messageformat2_errors.h" 27 28 // Auxiliary data structures used during formatting a message 29 30 U_NAMESPACE_BEGIN 31 32 namespace message2 { 33 34 namespace functions { 35 static constexpr std::u16string_view DATETIME = u"datetime"; 36 static constexpr std::u16string_view DATE = u"date"; 37 static constexpr std::u16string_view TIME = u"time"; 38 static constexpr std::u16string_view NUMBER = u"number"; 39 static constexpr std::u16string_view INTEGER = u"integer"; 40 static constexpr std::u16string_view TEST_FUNCTION = u"test:function"; 41 static constexpr std::u16string_view TEST_FORMAT = u"test:format"; 42 static constexpr std::u16string_view TEST_SELECT = u"test:select"; 43 static constexpr std::u16string_view STRING = u"string"; 44 } 45 46 using namespace data_model; 47 48 // PrioritizedVariant 49 50 // For how this class is used, see the references to (integer, variant) tuples 51 // in https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#pattern-selection 52 class PrioritizedVariant : public UObject { 53 public: 54 PrioritizedVariant() = default; 55 PrioritizedVariant(PrioritizedVariant&&) = default; 56 PrioritizedVariant& operator=(PrioritizedVariant&&) noexcept = default; 57 UBool operator<(const PrioritizedVariant&) const; 58 int32_t priority; 59 /* const */ SelectorKeys keys; 60 /* const */ Pattern pat; 61 PrioritizedVariant(uint32_t p, 62 const SelectorKeys& k, 63 const Pattern& pattern) noexcept : priority(p), keys(k), pat(pattern) {} 64 virtual ~PrioritizedVariant(); 65 }; // class PrioritizedVariant 66 67 static inline int32_t comparePrioritizedVariants(UElement left, UElement right) { 68 const PrioritizedVariant& tuple1 = *(static_cast<const PrioritizedVariant*>(left.pointer)); 69 const PrioritizedVariant& tuple2 = *(static_cast<const PrioritizedVariant*>(right.pointer)); 70 if (tuple1 < tuple2) { 71 return -1; 72 } 73 if (tuple1.priority == tuple2.priority) { 74 return 0; 75 } 76 return 1; 77 } 78 79 // Closures and environments 80 // ------------------------- 81 82 class Environment; 83 84 // A closure represents the right-hand side of a variable 85 // declaration, along with an environment giving values 86 // to its free variables 87 class Closure : public UMemory { 88 public: 89 const Expression& getExpr() const { 90 return expr; 91 } 92 const Environment& getEnv() const { 93 return env; 94 } 95 Closure(const Expression& expression, const Environment& environment) : expr(expression), env(environment) {} 96 Closure(Closure&&) = default; 97 98 virtual ~Closure(); 99 private: 100 101 // An unevaluated expression 102 const Expression& expr; 103 // The environment mapping names used in this 104 // expression to other expressions 105 const Environment& env; 106 }; 107 108 // An environment is represented as a linked chain of 109 // non-empty environments, terminating at an empty environment. 110 // It's searched using linear search. 111 class Environment : public UMemory { 112 public: 113 virtual bool has(const VariableName&) const = 0; 114 virtual const Closure& lookup(const VariableName&) const = 0; 115 static Environment* create(UErrorCode&); 116 static Environment* create(const VariableName&, Closure&&, Environment*, UErrorCode&); 117 virtual ~Environment(); 118 }; 119 120 class NonEmptyEnvironment; 121 class EmptyEnvironment : public Environment { 122 public: 123 EmptyEnvironment() = default; 124 virtual ~EmptyEnvironment(); 125 126 private: 127 friend class Environment; 128 129 bool has(const VariableName&) const override; 130 const Closure& lookup(const VariableName&) const override; 131 static EmptyEnvironment* create(UErrorCode&); 132 static NonEmptyEnvironment* create(const VariableName&, Closure&&, Environment*, UErrorCode&); 133 }; 134 135 class NonEmptyEnvironment : public Environment { 136 private: 137 friend class Environment; 138 139 bool has(const VariableName&) const override; 140 const Closure& lookup(const VariableName&) const override; 141 static NonEmptyEnvironment* create(const VariableName&, Closure&&, const Environment*, UErrorCode&); 142 virtual ~NonEmptyEnvironment(); 143 private: 144 friend class Environment; 145 146 NonEmptyEnvironment(const VariableName& v, Closure&& c, Environment* e) : var(v), rhs(std::move(c)), parent(e) {} 147 148 // Maps VariableName onto Closure* 149 // Chain of linked environments 150 VariableName var; 151 Closure rhs; 152 const LocalPointer<Environment> parent; 153 }; 154 155 // The context contains all the information needed to process 156 // an entire message: arguments, formatter cache, and error list 157 158 class MessageFormatter; 159 160 class MessageContext : public UMemory { 161 public: 162 MessageContext(const MessageArguments&, const StaticErrors&, UErrorCode&); 163 164 const Formattable* getGlobal(const VariableName&, UErrorCode&) const; 165 166 // If any errors were set, update `status` accordingly 167 void checkErrors(UErrorCode& status) const; 168 DynamicErrors& getErrors() { return errors; } 169 170 virtual ~MessageContext(); 171 172 private: 173 174 const MessageArguments& arguments; // External message arguments 175 // Errors accumulated during parsing/formatting 176 DynamicErrors errors; 177 178 }; // class MessageContext 179 180 // InternalValue 181 // ---------------- 182 183 class InternalValue : public UObject { 184 public: 185 const FunctionName& getFunctionName() const { return name; } 186 bool canSelect() const { return selector != nullptr; } 187 const Selector* getSelector(UErrorCode&) const; 188 FormattedPlaceholder forceFormatting(DynamicErrors& errs, 189 UErrorCode& errorCode); 190 void forceSelection(DynamicErrors& errs, 191 const UnicodeString* keys, 192 int32_t keysLen, 193 UnicodeString* prefs, 194 int32_t& prefsLen, 195 UErrorCode& errorCode); 196 // Needs to be deep-copyable and movable 197 virtual ~InternalValue(); 198 InternalValue(FormattedPlaceholder&&); 199 // Formatter and selector may be null 200 InternalValue(InternalValue*, FunctionOptions&&, const FunctionName&, const Formatter*, 201 const Selector*); 202 const UnicodeString& getFallback() const; 203 bool isFallback() const; 204 bool hasNullOperand() const; 205 // Can't be used anymore after calling this 206 FormattedPlaceholder takeArgument(UErrorCode& errorCode); 207 InternalValue(InternalValue&& other) { *this = std::move(other); } 208 InternalValue& operator=(InternalValue&& other) noexcept; 209 private: 210 // InternalValue is owned (if present) 211 std::variant<InternalValue*, FormattedPlaceholder> argument; 212 FunctionOptions options; 213 FunctionName name; 214 const Selector* selector; // May be null 215 const Formatter* formatter; // May be null, but one or the other should be non-null unless argument is a FormattedPlaceholder 216 bool checkSelectOption() const; 217 }; // class InternalValue 218 219 } // namespace message2 220 221 U_NAMESPACE_END 222 223 #endif /* #if !UCONFIG_NO_MF2 */ 224 225 #endif /* #if !UCONFIG_NO_FORMATTING */ 226 227 #endif /* #if !UCONFIG_NO_NORMALIZATION */ 228 229 #endif /* U_SHOW_CPLUSPLUS_API */ 230 231 #endif // MESSAGEFORMAT2_EVALUATION_H 232 233 #endif // U_HIDE_DEPRECATED_API 234 // eof