ICU-21254 Add plural rule parsing for exponent operand in C++

This commit is contained in:
Elango Cheran 2020-09-01 16:06:51 -07:00 committed by Elango
parent 82545ecc2c
commit cb7f197821
4 changed files with 99 additions and 0 deletions

View file

@ -56,6 +56,7 @@ static const UChar PK_VAR_N[]={LOW_N,0};
static const UChar PK_VAR_I[]={LOW_I,0};
static const UChar PK_VAR_F[]={LOW_F,0};
static const UChar PK_VAR_T[]={LOW_T,0};
static const UChar PK_VAR_E[]={LOW_E,0};
static const UChar PK_VAR_V[]={LOW_V,0};
static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
static const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
@ -600,6 +601,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tVariableI:
case tVariableF:
case tVariableT:
case tVariableE:
case tVariableV:
U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
@ -984,6 +986,8 @@ static UnicodeString tokenString(tokenType tok) {
s.append(LOW_V); break;
case tVariableT:
s.append(LOW_T); break;
case tVariableE:
s.append(LOW_E); break;
default:
s.append(TILDE);
}
@ -1160,6 +1164,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
case tVariableI:
case tVariableF:
case tVariableT:
case tVariableE:
case tVariableV:
if (type != tIs && type != tMod && type != tIn &&
type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
@ -1176,6 +1181,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type == tVariableI ||
type == tVariableF ||
type == tVariableT ||
type == tVariableE ||
type == tVariableV ||
type == tAt)) {
status = U_UNEXPECTED_TOKEN;
@ -1207,6 +1213,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type != tVariableI &&
type != tVariableF &&
type != tVariableT &&
type != tVariableE &&
type != tVariableV) {
status = U_UNEXPECTED_TOKEN;
}
@ -1384,6 +1391,8 @@ PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
keyType = tVariableF;
} else if (0 == token.compare(PK_VAR_T, 1)) {
keyType = tVariableT;
} else if (0 == token.compare(PK_VAR_E, 1)) {
keyType = tVariableE;
} else if (0 == token.compare(PK_VAR_V, 1)) {
keyType = tVariableV;
} else if (0 == token.compare(PK_IS, 2)) {
@ -1481,6 +1490,8 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
return PLURAL_OPERAND_V;
case tVariableT:
return PLURAL_OPERAND_T;
case tVariableE:
return PLURAL_OPERAND_E;
default:
UPRV_UNREACHABLE; // unexpected.
}

View file

@ -138,6 +138,7 @@ enum tokenType {
tVariableF,
tVariableV,
tVariableT,
tVariableE,
tDecimal,
tInteger,
tEOF

View file

@ -31,6 +31,7 @@
#include "number_decimalquantity.h"
using icu::number::impl::DecimalQuantity;
using namespace icu::number;
void setupResult(const int32_t testSource[], char result[], int32_t* max);
UBool checkEqual(const PluralRules &test, char *result, int32_t max);
@ -49,6 +50,7 @@ void PluralRulesTest::runIndexedTest( int32_t index, UBool exec, const char* &na
TESTCASE_AUTO(testGetSamples);
TESTCASE_AUTO(testWithin);
TESTCASE_AUTO(testGetAllKeywordValues);
TESTCASE_AUTO(testCompactDecimalPluralKeyword);
TESTCASE_AUTO(testOrdinal);
TESTCASE_AUTO(testSelect);
TESTCASE_AUTO(testAvailbleLocales);
@ -595,6 +597,88 @@ PluralRulesTest::testGetAllKeywordValues() {
}
}
void
PluralRulesTest::testCompactDecimalPluralKeyword() {
IcuTestErrorCode errorCode(*this, "testCompactDecimalPluralKeyword");
LocalPointer<PluralRules> rules(PluralRules::createRules(
u"one: i = 0,1 @integer 0, 1 @decimal 0.0~1.5; "
u"many: e = 0 and i % 1000000 = 0 and v = 0 or e != 0 .. 5; "
u"other: @integer 2~17, 100, 1000, 10000, 100000, 1000000, "
u" @decimal 2.0~3.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …", errorCode));
if (U_FAILURE(errorCode)) {
errln("Couldn't instantiate plurals rules from string, with error = %s", u_errorName(errorCode));
return;
}
const char* localeName = "fr-FR";
Locale locale = Locale::createFromName(localeName);
struct TestCase {
const char16_t* skeleton;
const int input;
const char16_t* expectedFormattedOutput;
const char16_t* expectedPluralRuleKeyword;
} cases[] = {
// unlocalized formatter skeleton, input, string output, plural rule keyword
{u"", 0, u"0", u"one"},
{u"compact-long", 0, u"0", u"one"},
{u"", 1, u"1", u"one"},
{u"compact-long", 1, u"1", u"one"},
{u"", 2, u"2", u"other"},
{u"compact-long", 2, u"2", u"other"},
{u"", 1000000, u"1000000", u"many"},
{u"compact-long", 1000000, u"1 million", u"many"},
{u"", 1000001, u"1000001", u"other"},
{u"compact-long", 1000001, u"1 million", u"many"},
{u"", 120000, u"1200000", u"other"},
{u"compact-long", 1200000, u"1,2 millions", u"many"},
{u"", 1200001, u"1200001", u"other"},
{u"compact-long", 1200001, u"1,2 millions", u"many"},
{u"", 2000000, u"2000000", u"many"},
{u"compact-long", 2000000, u"2 millions", u"many"},
};
for (const auto& cas : cases) {
const char16_t* skeleton = cas.skeleton;
const int input = cas.input;
const char16_t* expectedPluralRuleKeyword = cas.expectedPluralRuleKeyword;
UnicodeString actualPluralRuleKeyword =
getPluralKeyword(rules, locale, input, skeleton);
UnicodeString message(UnicodeString(localeName) + u" " + DoubleToUnicodeString(input));
assertEquals(message, expectedPluralRuleKeyword, actualPluralRuleKeyword);
}
}
UnicodeString PluralRulesTest::getPluralKeyword(const LocalPointer<PluralRules> &rules, Locale locale, double number, const char16_t* skeleton) {
IcuTestErrorCode errorCode(*this, "getPluralKeyword");
UnlocalizedNumberFormatter ulnf = NumberFormatter::forSkeleton(skeleton, errorCode);
if (errorCode.errIfFailureAndReset("PluralRules::getPluralKeyword(<PluralRules>, <locale>, %d, %s) failed", number, skeleton)) {
return nullptr;
}
LocalizedNumberFormatter formatter = ulnf.locale(locale);
const FormattedNumber fn = formatter.formatDouble(number, errorCode);
if (errorCode.errIfFailureAndReset("NumberFormatter::formatDouble(%d) failed", number)) {
return nullptr;
}
UnicodeString pluralKeyword = rules->select(fn, errorCode);
if (errorCode.errIfFailureAndReset("PluralRules->select(FormattedNumber of %d) failed", number)) {
return nullptr;
}
return pluralKeyword;
}
void PluralRulesTest::testOrdinal() {
IcuTestErrorCode errorCode(*this, "testOrdinal");
LocalPointer<PluralRules> pr(PluralRules::forLocale("en", UPLURAL_TYPE_ORDINAL, errorCode));

View file

@ -32,6 +32,7 @@ private:
void testGetSamples();
void testWithin();
void testGetAllKeywordValues();
void testCompactDecimalPluralKeyword();
void testOrdinal();
void testSelect();
void testAvailbleLocales();
@ -43,6 +44,8 @@ private:
void assertRuleValue(const UnicodeString& rule, double expected);
void assertRuleKeyValue(const UnicodeString& rule, const UnicodeString& key,
double expected);
UnicodeString getPluralKeyword(const LocalPointer<PluralRules> &rules,
Locale locale, double number, const char16_t* skeleton);
void checkSelect(const LocalPointer<PluralRules> &rules, UErrorCode &status,
int32_t line, const char *keyword, ...);
void compareLocaleResults(const char* loc1, const char* loc2, const char* loc3);