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 clearState()30 void MessageFormatter::Builder::clearState() { 31 normalizedInput.remove(); 32 delete errors; 33 errors = nullptr; 34 } 35 setPattern(const UnicodeString & pat,UParseError & parseError,UErrorCode & errorCode)36 MessageFormatter::Builder& MessageFormatter::Builder::setPattern(const UnicodeString& pat, 37 UParseError& parseError, 38 UErrorCode& errorCode) { 39 clearState(); 40 // Create errors 41 errors = create<StaticErrors>(StaticErrors(errorCode), errorCode); 42 THIS_ON_ERROR(errorCode); 43 44 // Parse the pattern 45 MFDataModel::Builder tree(errorCode); 46 Parser(pat, tree, *errors, normalizedInput).parse(parseError, errorCode); 47 48 // Fail on syntax errors 49 if (errors->hasSyntaxError()) { 50 errors->checkErrors(errorCode); 51 // Check that the checkErrors() method set the error code 52 U_ASSERT(U_FAILURE(errorCode)); 53 } 54 55 // Build the data model based on what was parsed 56 dataModel = tree.build(errorCode); 57 hasDataModel = true; 58 hasPattern = true; 59 pattern = pat; 60 61 return *this; 62 } 63 64 // Precondition: `reg` is non-null 65 // Does not adopt `reg` setFunctionRegistry(const MFFunctionRegistry & reg)66 MessageFormatter::Builder& MessageFormatter::Builder::setFunctionRegistry(const MFFunctionRegistry& reg) { 67 customMFFunctionRegistry = ® 68 return *this; 69 } 70 setLocale(const Locale & loc)71 MessageFormatter::Builder& MessageFormatter::Builder::setLocale(const Locale& loc) { 72 locale = loc; 73 return *this; 74 } 75 setDataModel(MFDataModel && newDataModel)76 MessageFormatter::Builder& MessageFormatter::Builder::setDataModel(MFDataModel&& newDataModel) { 77 clearState(); 78 hasPattern = false; 79 hasDataModel = true; 80 dataModel = std::move(newDataModel); 81 82 return *this; 83 } 84 85 MessageFormatter::Builder& setErrorHandlingBehavior(MessageFormatter::UMFErrorHandlingBehavior type)86 MessageFormatter::Builder::setErrorHandlingBehavior( 87 MessageFormatter::UMFErrorHandlingBehavior type) { 88 signalErrors = type == U_MF_STRICT; 89 return *this; 90 } 91 92 /* 93 This build() method is non-destructive, which entails the risk that 94 its borrowed MFFunctionRegistry and (if the setDataModel() method was called) 95 MFDataModel pointers could become invalidated. 96 */ build(UErrorCode & errorCode) const97 MessageFormatter MessageFormatter::Builder::build(UErrorCode& errorCode) const { 98 return MessageFormatter(*this, errorCode); 99 } 100 Builder(UErrorCode & errorCode)101 MessageFormatter::Builder::Builder(UErrorCode& errorCode) : locale(Locale::getDefault()), customMFFunctionRegistry(nullptr) { 102 // Initialize errors 103 errors = new StaticErrors(errorCode); 104 CHECK_ERROR(errorCode); 105 if (errors == nullptr) { 106 errorCode = U_MEMORY_ALLOCATION_ERROR; 107 } 108 } 109 ~Builder()110 MessageFormatter::Builder::~Builder() { 111 if (errors != nullptr) { 112 delete errors; 113 errors = nullptr; 114 } 115 } 116 117 // MessageFormatter 118 MessageFormatter(const MessageFormatter::Builder & builder,UErrorCode & success)119 MessageFormatter::MessageFormatter(const MessageFormatter::Builder& builder, UErrorCode &success) : locale(builder.locale), customMFFunctionRegistry(builder.customMFFunctionRegistry) { 120 CHECK_ERROR(success); 121 122 // Set up the standard function registry 123 MFFunctionRegistry::Builder standardFunctionsBuilder(success); 124 125 FormatterFactory* dateTime = StandardFunctions::DateTimeFactory::dateTime(success); 126 FormatterFactory* date = StandardFunctions::DateTimeFactory::date(success); 127 FormatterFactory* time = StandardFunctions::DateTimeFactory::time(success); 128 FormatterFactory* number = new StandardFunctions::NumberFactory(); 129 FormatterFactory* integer = new StandardFunctions::IntegerFactory(); 130 standardFunctionsBuilder.adoptFormatter(FunctionName(UnicodeString("datetime")), dateTime, success) 131 .adoptFormatter(FunctionName(UnicodeString("date")), date, success) 132 .adoptFormatter(FunctionName(UnicodeString("time")), time, success) 133 .adoptFormatter(FunctionName(UnicodeString("number")), number, success) 134 .adoptFormatter(FunctionName(UnicodeString("integer")), integer, success) 135 .adoptSelector(FunctionName(UnicodeString("number")), new StandardFunctions::PluralFactory(UPLURAL_TYPE_CARDINAL), success) 136 .adoptSelector(FunctionName(UnicodeString("integer")), new StandardFunctions::PluralFactory(StandardFunctions::PluralFactory::integer()), success) 137 .adoptSelector(FunctionName(UnicodeString("string")), new StandardFunctions::TextFactory(), success); 138 CHECK_ERROR(success); 139 standardMFFunctionRegistry = standardFunctionsBuilder.build(); 140 CHECK_ERROR(success); 141 standardMFFunctionRegistry.checkStandard(); 142 143 normalizedInput = builder.normalizedInput; 144 signalErrors = builder.signalErrors; 145 146 // Build data model 147 // First, check that there is a data model 148 // (which might have been set by setDataModel(), or to 149 // the data model parsed from the pattern by setPattern()) 150 151 if (!builder.hasDataModel) { 152 success = U_INVALID_STATE_ERROR; 153 return; 154 } 155 156 dataModel = builder.dataModel; 157 if (builder.errors != nullptr) { 158 errors = new StaticErrors(*builder.errors, success); 159 } else { 160 // Initialize errors 161 LocalPointer<StaticErrors> errorsNew(new StaticErrors(success)); 162 CHECK_ERROR(success); 163 errors = errorsNew.orphan(); 164 } 165 166 // Note: we currently evaluate variables lazily, 167 // without memoization. This call is still necessary 168 // to check out-of-scope uses of local variables in 169 // right-hand sides (unresolved variable errors can 170 // only be checked when arguments are known) 171 172 // Check for resolution errors 173 Checker(dataModel, *errors).check(success); 174 } 175 cleanup()176 void MessageFormatter::cleanup() noexcept { 177 if (errors != nullptr) { 178 delete errors; 179 errors = nullptr; 180 } 181 } 182 operator =(MessageFormatter && other)183 MessageFormatter& MessageFormatter::operator=(MessageFormatter&& other) noexcept { 184 cleanup(); 185 186 locale = std::move(other.locale); 187 standardMFFunctionRegistry = std::move(other.standardMFFunctionRegistry); 188 customMFFunctionRegistry = other.customMFFunctionRegistry; 189 dataModel = std::move(other.dataModel); 190 normalizedInput = std::move(other.normalizedInput); 191 signalErrors = other.signalErrors; 192 errors = other.errors; 193 other.errors = nullptr; 194 return *this; 195 } 196 getDataModel() const197 const MFDataModel& MessageFormatter::getDataModel() const { return dataModel; } 198 getPattern() const199 UnicodeString MessageFormatter::getPattern() const { 200 // Converts the current data model back to a string 201 UnicodeString result; 202 Serializer serializer(getDataModel(), result); 203 serializer.serialize(); 204 return result; 205 } 206 207 // Precondition: custom function registry exists getCustomMFFunctionRegistry() const208 const MFFunctionRegistry& MessageFormatter::getCustomMFFunctionRegistry() const { 209 U_ASSERT(hasCustomMFFunctionRegistry()); 210 return *customMFFunctionRegistry; 211 } 212 ~MessageFormatter()213 MessageFormatter::~MessageFormatter() { 214 cleanup(); 215 } 216 217 // Selector and formatter lookup 218 // ----------------------------- 219 220 // Postcondition: selector != nullptr || U_FAILURE(status) getSelector(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const221 Selector* MessageFormatter::getSelector(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const { 222 NULL_ON_ERROR(status); 223 U_ASSERT(isSelector(functionName)); 224 225 const SelectorFactory* selectorFactory = lookupSelectorFactory(context, functionName, status); 226 NULL_ON_ERROR(status); 227 if (selectorFactory == nullptr) { 228 status = U_MEMORY_ALLOCATION_ERROR; 229 return nullptr; 230 } 231 // Create a specific instance of the selector 232 auto result = selectorFactory->createSelector(getLocale(), status); 233 NULL_ON_ERROR(status); 234 return result; 235 } 236 237 // Returns an owned pointer getFormatter(const FunctionName & functionName,UErrorCode & status) const238 Formatter* MessageFormatter::getFormatter(const FunctionName& functionName, UErrorCode& status) const { 239 NULL_ON_ERROR(status); 240 241 // Create the formatter 242 243 // First, look up the formatter factory for this function 244 FormatterFactory* formatterFactory = lookupFormatterFactory(functionName, status); 245 NULL_ON_ERROR(status); 246 247 U_ASSERT(formatterFactory != nullptr); 248 249 // Create a specific instance of the formatter 250 Formatter* formatter = formatterFactory->createFormatter(locale, status); 251 NULL_ON_ERROR(status); 252 if (formatter == nullptr) { 253 status = U_MEMORY_ALLOCATION_ERROR; 254 return nullptr; 255 } 256 return formatter; 257 } 258 getDefaultFormatterNameByType(const UnicodeString & type,FunctionName & name) const259 bool MessageFormatter::getDefaultFormatterNameByType(const UnicodeString& type, FunctionName& name) const { 260 U_ASSERT(hasCustomMFFunctionRegistry()); 261 const MFFunctionRegistry& reg = getCustomMFFunctionRegistry(); 262 return reg.getDefaultFormatterNameByType(type, name); 263 } 264 265 // --------------------------------------------------- 266 // Function registry 267 isBuiltInSelector(const FunctionName & functionName) const268 bool MessageFormatter::isBuiltInSelector(const FunctionName& functionName) const { 269 return standardMFFunctionRegistry.hasSelector(functionName); 270 } 271 isBuiltInFormatter(const FunctionName & functionName) const272 bool MessageFormatter::isBuiltInFormatter(const FunctionName& functionName) const { 273 return standardMFFunctionRegistry.hasFormatter(functionName); 274 } 275 276 // https://github.com/unicode-org/message-format-wg/issues/409 277 // Unknown function = unknown function error 278 // Formatter used as selector = selector error 279 // Selector used as formatter = formatting error lookupSelectorFactory(MessageContext & context,const FunctionName & functionName,UErrorCode & status) const280 const SelectorFactory* MessageFormatter::lookupSelectorFactory(MessageContext& context, const FunctionName& functionName, UErrorCode& status) const { 281 DynamicErrors& err = context.getErrors(); 282 283 if (isBuiltInSelector(functionName)) { 284 return standardMFFunctionRegistry.getSelector(functionName); 285 } 286 if (isBuiltInFormatter(functionName)) { 287 err.setSelectorError(functionName, status); 288 return nullptr; 289 } 290 if (hasCustomMFFunctionRegistry()) { 291 const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry(); 292 const SelectorFactory* selectorFactory = customMFFunctionRegistry.getSelector(functionName); 293 if (selectorFactory != nullptr) { 294 return selectorFactory; 295 } 296 if (customMFFunctionRegistry.getFormatter(functionName) != nullptr) { 297 err.setSelectorError(functionName, status); 298 return nullptr; 299 } 300 } 301 // Either there is no custom function registry and the function 302 // isn't built-in, or the function doesn't exist in either the built-in 303 // or custom registry. 304 // Unknown function error 305 err.setUnknownFunction(functionName, status); 306 return nullptr; 307 } 308 lookupFormatterFactory(const FunctionName & functionName,UErrorCode & status) const309 FormatterFactory* MessageFormatter::lookupFormatterFactory(const FunctionName& functionName, 310 UErrorCode& status) const { 311 NULL_ON_ERROR(status); 312 313 if (isBuiltInFormatter(functionName)) { 314 return standardMFFunctionRegistry.getFormatter(functionName); 315 } 316 if (isBuiltInSelector(functionName)) { 317 status = U_MF_FORMATTING_ERROR; 318 return nullptr; 319 } 320 if (hasCustomMFFunctionRegistry()) { 321 const MFFunctionRegistry& customMFFunctionRegistry = getCustomMFFunctionRegistry(); 322 FormatterFactory* formatterFactory = customMFFunctionRegistry.getFormatter(functionName); 323 if (formatterFactory != nullptr) { 324 return formatterFactory; 325 } 326 if (customMFFunctionRegistry.getSelector(functionName) != nullptr) { 327 status = U_MF_FORMATTING_ERROR; 328 return nullptr; 329 } 330 } 331 // Either there is no custom function registry and the function 332 // isn't built-in, or the function doesn't exist in either the built-in 333 // or custom registry. 334 // Unknown function error 335 status = U_MF_UNKNOWN_FUNCTION_ERROR; 336 return nullptr; 337 } 338 isCustomFormatter(const FunctionName & fn) const339 bool MessageFormatter::isCustomFormatter(const FunctionName& fn) const { 340 return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getFormatter(fn) != nullptr; 341 } 342 343 isCustomSelector(const FunctionName & fn) const344 bool MessageFormatter::isCustomSelector(const FunctionName& fn) const { 345 return hasCustomMFFunctionRegistry() && getCustomMFFunctionRegistry().getSelector(fn) != nullptr; 346 } 347 348 } // namespace message2 349 350 U_NAMESPACE_END 351 352 #endif /* #if !UCONFIG_NO_MF2 */ 353 354 #endif /* #if !UCONFIG_NO_FORMATTING */ 355