Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions icu4c/source/i18n/plurrule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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) {
Expand All @@ -1176,6 +1181,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type == tVariableI ||
type == tVariableF ||
type == tVariableT ||
type == tVariableE ||
type == tVariableV ||
type == tAt)) {
status = U_UNEXPECTED_TOKEN;
Expand Down Expand Up @@ -1207,6 +1213,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type != tVariableI &&
type != tVariableF &&
type != tVariableT &&
type != tVariableE &&
type != tVariableV) {
status = U_UNEXPECTED_TOKEN;
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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.
}
Expand Down
1 change: 1 addition & 0 deletions icu4c/source/i18n/plurrule_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ enum tokenType {
tVariableF,
tVariableV,
tVariableT,
tVariableE,
tDecimal,
tInteger,
tEOF
Expand Down
84 changes: 84 additions & 0 deletions icu4c/source/test/intltest/plurults.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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"1 000 000", u"many"},
{u"compact-long", 1000000, u"1 million", u"many"},

{u"", 1000001, u"1 000 001", u"other"},
{u"compact-long", 1000001, u"1 million", u"many"},

{u"", 120000, u"1 200 000", u"other"},
{u"compact-long", 1200000, u"1,2 millions", u"many"},

{u"", 1200001, u"1 200 001", u"other"},
{u"compact-long", 1200001, u"1,2 millions", u"many"},

{u"", 2000000, u"2 000 000", 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));
Expand Down
3 changes: 3 additions & 0 deletions icu4c/source/test/intltest/plurults.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class PluralRulesTest : public IntlTest {
void testGetSamples();
void testWithin();
void testGetAllKeywordValues();
void testCompactDecimalPluralKeyword();
void testOrdinal();
void testSelect();
void testAvailbleLocales();
Expand All @@ -43,6 +44,8 @@ class PluralRulesTest : public IntlTest {
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);
Expand Down