Skip to content

Commit d5e887a

Browse files
committed
temp
1 parent 676c1a9 commit d5e887a

9 files changed

+281
-279
lines changed

icu4c/source/i18n/messageformat2.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,11 @@ FunctionContext MessageFormatter::makeFunctionContext(const FunctionOptions& opt
342342
context.getErrors().setFormattingError(functionName, status);
343343
return env.createFallback(fallbackStr, status);
344344
}
345+
if (status == U_MF_BAD_OPTION) {
346+
status = U_ZERO_ERROR;
347+
context.getErrors().setBadOption(functionName, status);
348+
return env.createFallback(fallbackStr, status);
349+
}
345350
if (U_FAILURE(status)) {
346351
return env.bogus();
347352
}
@@ -440,7 +445,16 @@ void MessageFormatter::formatPattern(MessageContext& context,
440445
const FunctionValue* val = partVal.getValue(status);
441446
// Shouldn't be null or a fallback
442447
U_ASSERT(U_SUCCESS(status));
448+
449+
// See comment in matchSelectorKeys()
450+
bool badSelectOption = !checkSelectOption(*val);
443451
result += val->formatToString(status);
452+
453+
if (badSelectOption) {
454+
context.getErrors().setRecoverableBadOption(val->getFunctionName(), status);
455+
CHECK_ERROR(status);
456+
}
457+
444458
// Handle formatting errors. `formatToString()` can't take a context and thus can't
445459
// register an error directly
446460
if (status == U_MF_FORMATTING_ERROR) {
@@ -490,6 +504,30 @@ void MessageFormatter::resolveSelectors(MessageContext& context, Environment& en
490504
}
491505
}
492506

507+
bool MessageFormatter::checkSelectOption(const FunctionValue& val) const {
508+
const UnicodeString& name = val.getFunctionName();
509+
510+
if (name != UnicodeString("number") && name != UnicodeString("integer")) {
511+
return true;
512+
}
513+
514+
// Per the spec, if the "select" option is present, it must have been
515+
// set from a literal
516+
517+
// Returns false if the `select` option is present and it was not set from a literal
518+
519+
const FunctionOptions& opts = val.getResolvedOptions();
520+
521+
// OK if the option wasn't present
522+
UErrorCode localErrorCode = U_ZERO_ERROR;
523+
opts.getFunctionOption(options::SELECT, localErrorCode);
524+
if (U_FAILURE(localErrorCode)) {
525+
return true;
526+
}
527+
// Otherwise, return true if the option was set from a literal
528+
return opts.wasSetFromLiteral(options::SELECT);
529+
}
530+
493531
// See https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#resolve-preferences
494532
// `keys` and `matches` are vectors of strings
495533
void MessageFormatter::matchSelectorKeys(const UVector& keys,
@@ -531,10 +569,27 @@ void MessageFormatter::matchSelectorKeys(const UVector& keys,
531569
// Call the selector
532570
// Caller checked for fallback, so it's safe to call getValue()
533571
const FunctionValue* rvVal = rv.getValue(status);
572+
573+
// This condition can't be checked in the selector.
574+
// Effectively, there are two different kinds of "bad option" errors:
575+
// one that can be recovered from (used for select=$var) and one that
576+
// can't (used for bad digit size options and other cases).
577+
// The checking of the recoverable error has to be done here; otherwise,
578+
// the "bad option" signaled by the selector implementation would cause
579+
// fallback output to be used when formatting the `*` pattern.
580+
bool badSelectOption = !checkSelectOption(*rvVal);
581+
534582
U_ASSERT(U_SUCCESS(status));
535583
rvVal->selectKeys(adoptedKeys.getAlias(), keysLen, prefsArr, prefsLen,
536584
status);
537585

586+
if (badSelectOption) {
587+
context.getErrors().setRecoverableBadOption(rvVal->getFunctionName(), status);
588+
CHECK_ERROR(status);
589+
// In this case, only the `*` variant should match
590+
prefsLen = 0;
591+
}
592+
538593
// Update errors
539594
if (savedStatus != status) {
540595
if (U_FAILURE(status)) {

icu4c/source/i18n/messageformat2_errors.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ namespace message2 {
3434
}
3535

3636
void DynamicErrors::setRecoverableBadOption(const FunctionName& formatterName, UErrorCode& status) {
37-
addError(DynamicError(DynamicErrorType::RecoverableBadOptionError, formatterName), status);
37+
// FIXME: do any tests actually require recoverability?
38+
addError(DynamicError(DynamicErrorType::/*Recoverable*/BadOptionError, formatterName), status);
3839
}
3940

4041
void DynamicErrors::setOperandMismatchError(const FunctionName& formatterName, UErrorCode& status) {

icu4c/source/i18n/messageformat2_evaluation.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ FunctionOptions::FunctionOptions(UVector&& optionsVector, UErrorCode& status) {
9393
}
9494

9595
// Returns false if option doesn't exist
96-
UBool FunctionOptions::wasSetFromLiteral(const UnicodeString& key) const {
96+
UBool FunctionOptions::wasSetFromLiteral(const std::u16string_view key) const {
9797
if (options == nullptr) {
9898
U_ASSERT(functionOptionsLen == 0);
9999
}
@@ -106,7 +106,8 @@ UBool FunctionOptions::wasSetFromLiteral(const UnicodeString& key) const {
106106
return false;
107107
}
108108

109-
FunctionOptions::getFunctionOption(const UnicodeString& key,
109+
const FunctionValue*
110+
FunctionOptions::getFunctionOption(std::u16string_view key,
110111
UErrorCode& status) const {
111112
if (options == nullptr) {
112113
U_ASSERT(functionOptionsLen == 0);
@@ -121,9 +122,8 @@ FunctionOptions::getFunctionOption(const UnicodeString& key,
121122
return nullptr;
122123
}
123124

124-
125125
UnicodeString
126-
FunctionOptions::getStringFunctionOption(const UnicodeString& k, UErrorCode& errorCode) const {
126+
FunctionOptions::getStringFunctionOption(std::u16string_view k, UErrorCode& errorCode) const {
127127
const FunctionValue* option = getFunctionOption(k, errorCode);
128128
if (U_SUCCESS(errorCode)) {
129129
UnicodeString result = option->formatToString(errorCode);
@@ -134,7 +134,7 @@ FunctionOptions::getStringFunctionOption(const UnicodeString& k, UErrorCode& err
134134
return {};
135135
}
136136

137-
UnicodeString FunctionOptions::getStringFunctionOption(const UnicodeString& key) const {
137+
UnicodeString FunctionOptions::getStringFunctionOption(std::u16string_view key) const {
138138
UErrorCode localStatus = U_ZERO_ERROR;
139139

140140
UnicodeString result = getStringFunctionOption(key, localStatus);
@@ -488,6 +488,7 @@ PrioritizedVariant::~PrioritizedVariant() {}
488488
// InternalValue
489489
// -------------
490490

491+
#if false
491492
InternalValue::InternalValue(FormattedPlaceholder&& arg) {
492493
argument = std::move(arg);
493494
selector = nullptr;
@@ -704,6 +705,7 @@ PrioritizedVariant::~PrioritizedVariant() {}
704705
argument = nullptr;
705706
}
706707
}
708+
#endif
707709

708710
} // namespace message2
709711
U_NAMESPACE_END

icu4c/source/i18n/messageformat2_formattable.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ namespace message2 {
172172
return number::NumberFormatter::withLocale(locale).formatDecimal(toFormat, errorCode);
173173
}
174174

175-
DateFormat* defaultDateTimeInstance(const Locale& locale, UErrorCode& errorCode) {
175+
static DateFormat* defaultDateTimeInstance(const Locale& locale, UErrorCode& errorCode) {
176176
NULL_ON_ERROR(errorCode);
177177
LocalPointer<DateFormat> df(DateFormat::createDateTimeInstance(DateFormat::SHORT, DateFormat::SHORT, locale));
178178
if (!df.isValid()) {
@@ -182,12 +182,34 @@ namespace message2 {
182182
return df.orphan();
183183
}
184184

185-
void formatDateWithDefaults(const Locale& locale, UDate date, UnicodeString& result, UErrorCode& errorCode) {
185+
TimeZone* createTimeZone(const DateInfo& dateInfo, UErrorCode& errorCode) {
186+
NULL_ON_ERROR(errorCode);
187+
188+
TimeZone* tz;
189+
if (dateInfo.zoneId.isEmpty()) {
190+
// Floating time value -- use default time zone
191+
tz = TimeZone::createDefault();
192+
} else {
193+
tz = TimeZone::createTimeZone(dateInfo.zoneId);
194+
}
195+
if (tz == nullptr) {
196+
errorCode = U_MEMORY_ALLOCATION_ERROR;
197+
}
198+
return tz;
199+
}
200+
201+
void formatDateWithDefaults(const Locale& locale,
202+
const DateInfo& dateInfo,
203+
UnicodeString& result,
204+
UErrorCode& errorCode) {
186205
CHECK_ERROR(errorCode);
187206

188207
LocalPointer<DateFormat> df(defaultDateTimeInstance(locale, errorCode));
189208
CHECK_ERROR(errorCode);
190-
df->format(date, result, 0, errorCode);
209+
210+
df->adoptTimeZone(createTimeZone(dateInfo, errorCode));
211+
CHECK_ERROR(errorCode);
212+
df->format(dateInfo.date, result, nullptr, errorCode);
191213
}
192214

193215
static UnicodeString& handleBiDi(const Locale& locale,
@@ -245,7 +267,7 @@ namespace message2 {
245267
case UFMT_DATE: {
246268
const DateInfo* dateInfo = toFormat.getDate(status);
247269
U_ASSERT(U_SUCCESS(status));
248-
formatDateWithDefaults(locale, d, result, status);
270+
formatDateWithDefaults(locale, *dateInfo, result, status);
249271
break;
250272
}
251273
case UFMT_DOUBLE: {

0 commit comments

Comments
 (0)