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