Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
michael@0 | 1 | /* |
michael@0 | 2 | ******************************************************************************* |
michael@0 | 3 | * Copyright (C) 2007-2013, International Business Machines Corporation and |
michael@0 | 4 | * others. All Rights Reserved. |
michael@0 | 5 | ******************************************************************************* |
michael@0 | 6 | * |
michael@0 | 7 | * File PLURRULE_IMPL.H |
michael@0 | 8 | * |
michael@0 | 9 | ******************************************************************************* |
michael@0 | 10 | */ |
michael@0 | 11 | |
michael@0 | 12 | |
michael@0 | 13 | #ifndef PLURRULE_IMPLE |
michael@0 | 14 | #define PLURRULE_IMPLE |
michael@0 | 15 | |
michael@0 | 16 | // Internal definitions for the PluralRules implementation. |
michael@0 | 17 | |
michael@0 | 18 | #if !UCONFIG_NO_FORMATTING |
michael@0 | 19 | |
michael@0 | 20 | #include "unicode/format.h" |
michael@0 | 21 | #include "unicode/locid.h" |
michael@0 | 22 | #include "unicode/parseerr.h" |
michael@0 | 23 | #include "unicode/ures.h" |
michael@0 | 24 | #include "unicode/utypes.h" |
michael@0 | 25 | #include "uvector.h" |
michael@0 | 26 | #include "hash.h" |
michael@0 | 27 | |
michael@0 | 28 | class PluralRulesTest; |
michael@0 | 29 | |
michael@0 | 30 | U_NAMESPACE_BEGIN |
michael@0 | 31 | |
michael@0 | 32 | class AndConstraint; |
michael@0 | 33 | class RuleChain; |
michael@0 | 34 | |
michael@0 | 35 | static const UChar DOT = ((UChar)0x002E); |
michael@0 | 36 | static const UChar SINGLE_QUOTE = ((UChar)0x0027); |
michael@0 | 37 | static const UChar SLASH = ((UChar)0x002F); |
michael@0 | 38 | static const UChar BACKSLASH = ((UChar)0x005C); |
michael@0 | 39 | static const UChar SPACE = ((UChar)0x0020); |
michael@0 | 40 | static const UChar EXCLAMATION = ((UChar)0x0021); |
michael@0 | 41 | static const UChar QUOTATION_MARK = ((UChar)0x0022); |
michael@0 | 42 | static const UChar NUMBER_SIGN = ((UChar)0x0023); |
michael@0 | 43 | static const UChar PERCENT_SIGN = ((UChar)0x0025); |
michael@0 | 44 | static const UChar ASTERISK = ((UChar)0x002A); |
michael@0 | 45 | static const UChar COMMA = ((UChar)0x002C); |
michael@0 | 46 | static const UChar HYPHEN = ((UChar)0x002D); |
michael@0 | 47 | static const UChar U_ZERO = ((UChar)0x0030); |
michael@0 | 48 | static const UChar U_ONE = ((UChar)0x0031); |
michael@0 | 49 | static const UChar U_TWO = ((UChar)0x0032); |
michael@0 | 50 | static const UChar U_THREE = ((UChar)0x0033); |
michael@0 | 51 | static const UChar U_FOUR = ((UChar)0x0034); |
michael@0 | 52 | static const UChar U_FIVE = ((UChar)0x0035); |
michael@0 | 53 | static const UChar U_SIX = ((UChar)0x0036); |
michael@0 | 54 | static const UChar U_SEVEN = ((UChar)0x0037); |
michael@0 | 55 | static const UChar U_EIGHT = ((UChar)0x0038); |
michael@0 | 56 | static const UChar U_NINE = ((UChar)0x0039); |
michael@0 | 57 | static const UChar COLON = ((UChar)0x003A); |
michael@0 | 58 | static const UChar SEMI_COLON = ((UChar)0x003B); |
michael@0 | 59 | static const UChar EQUALS = ((UChar)0x003D); |
michael@0 | 60 | static const UChar AT = ((UChar)0x0040); |
michael@0 | 61 | static const UChar CAP_A = ((UChar)0x0041); |
michael@0 | 62 | static const UChar CAP_B = ((UChar)0x0042); |
michael@0 | 63 | static const UChar CAP_R = ((UChar)0x0052); |
michael@0 | 64 | static const UChar CAP_Z = ((UChar)0x005A); |
michael@0 | 65 | static const UChar LOWLINE = ((UChar)0x005F); |
michael@0 | 66 | static const UChar LEFTBRACE = ((UChar)0x007B); |
michael@0 | 67 | static const UChar RIGHTBRACE = ((UChar)0x007D); |
michael@0 | 68 | static const UChar TILDE = ((UChar)0x007E); |
michael@0 | 69 | static const UChar ELLIPSIS = ((UChar)0x2026); |
michael@0 | 70 | |
michael@0 | 71 | static const UChar LOW_A = ((UChar)0x0061); |
michael@0 | 72 | static const UChar LOW_B = ((UChar)0x0062); |
michael@0 | 73 | static const UChar LOW_C = ((UChar)0x0063); |
michael@0 | 74 | static const UChar LOW_D = ((UChar)0x0064); |
michael@0 | 75 | static const UChar LOW_E = ((UChar)0x0065); |
michael@0 | 76 | static const UChar LOW_F = ((UChar)0x0066); |
michael@0 | 77 | static const UChar LOW_G = ((UChar)0x0067); |
michael@0 | 78 | static const UChar LOW_H = ((UChar)0x0068); |
michael@0 | 79 | static const UChar LOW_I = ((UChar)0x0069); |
michael@0 | 80 | static const UChar LOW_J = ((UChar)0x006a); |
michael@0 | 81 | static const UChar LOW_K = ((UChar)0x006B); |
michael@0 | 82 | static const UChar LOW_L = ((UChar)0x006C); |
michael@0 | 83 | static const UChar LOW_M = ((UChar)0x006D); |
michael@0 | 84 | static const UChar LOW_N = ((UChar)0x006E); |
michael@0 | 85 | static const UChar LOW_O = ((UChar)0x006F); |
michael@0 | 86 | static const UChar LOW_P = ((UChar)0x0070); |
michael@0 | 87 | static const UChar LOW_Q = ((UChar)0x0071); |
michael@0 | 88 | static const UChar LOW_R = ((UChar)0x0072); |
michael@0 | 89 | static const UChar LOW_S = ((UChar)0x0073); |
michael@0 | 90 | static const UChar LOW_T = ((UChar)0x0074); |
michael@0 | 91 | static const UChar LOW_U = ((UChar)0x0075); |
michael@0 | 92 | static const UChar LOW_V = ((UChar)0x0076); |
michael@0 | 93 | static const UChar LOW_W = ((UChar)0x0077); |
michael@0 | 94 | static const UChar LOW_Y = ((UChar)0x0079); |
michael@0 | 95 | static const UChar LOW_Z = ((UChar)0x007A); |
michael@0 | 96 | |
michael@0 | 97 | |
michael@0 | 98 | static const int32_t PLURAL_RANGE_HIGH = 0x7fffffff; |
michael@0 | 99 | |
michael@0 | 100 | enum tokenType { |
michael@0 | 101 | none, |
michael@0 | 102 | tNumber, |
michael@0 | 103 | tComma, |
michael@0 | 104 | tSemiColon, |
michael@0 | 105 | tSpace, |
michael@0 | 106 | tColon, |
michael@0 | 107 | tAt, // '@' |
michael@0 | 108 | tDot, |
michael@0 | 109 | tDot2, |
michael@0 | 110 | tEllipsis, |
michael@0 | 111 | tKeyword, |
michael@0 | 112 | tAnd, |
michael@0 | 113 | tOr, |
michael@0 | 114 | tMod, // 'mod' or '%' |
michael@0 | 115 | tNot, // 'not' only. |
michael@0 | 116 | tIn, // 'in' only. |
michael@0 | 117 | tEqual, // '=' only. |
michael@0 | 118 | tNotEqual, // '!=' |
michael@0 | 119 | tTilde, |
michael@0 | 120 | tWithin, |
michael@0 | 121 | tIs, |
michael@0 | 122 | tVariableN, |
michael@0 | 123 | tVariableI, |
michael@0 | 124 | tVariableF, |
michael@0 | 125 | tVariableV, |
michael@0 | 126 | tVariableT, |
michael@0 | 127 | tDecimal, |
michael@0 | 128 | tInteger, |
michael@0 | 129 | tEOF |
michael@0 | 130 | }; |
michael@0 | 131 | |
michael@0 | 132 | |
michael@0 | 133 | class PluralRuleParser: public UMemory { |
michael@0 | 134 | public: |
michael@0 | 135 | PluralRuleParser(); |
michael@0 | 136 | virtual ~PluralRuleParser(); |
michael@0 | 137 | |
michael@0 | 138 | void parse(const UnicodeString &rules, PluralRules *dest, UErrorCode &status); |
michael@0 | 139 | void getNextToken(UErrorCode &status); |
michael@0 | 140 | void checkSyntax(UErrorCode &status); |
michael@0 | 141 | static int32_t getNumberValue(const UnicodeString &token); |
michael@0 | 142 | |
michael@0 | 143 | private: |
michael@0 | 144 | static tokenType getKeyType(const UnicodeString& token, tokenType type); |
michael@0 | 145 | static tokenType charType(UChar ch); |
michael@0 | 146 | static UBool isValidKeyword(const UnicodeString& token); |
michael@0 | 147 | |
michael@0 | 148 | const UnicodeString *ruleSrc; // The rules string. |
michael@0 | 149 | int32_t ruleIndex; // String index in the input rules, the current parse position. |
michael@0 | 150 | UnicodeString token; // Token most recently scanned. |
michael@0 | 151 | tokenType type; |
michael@0 | 152 | tokenType prevType; |
michael@0 | 153 | |
michael@0 | 154 | // The items currently being parsed & built. |
michael@0 | 155 | // Note: currentChain may not be the last RuleChain in the |
michael@0 | 156 | // list because the "other" chain is forced to the end. |
michael@0 | 157 | AndConstraint *curAndConstraint; |
michael@0 | 158 | RuleChain *currentChain; |
michael@0 | 159 | |
michael@0 | 160 | int32_t rangeLowIdx; // Indices in the UVector of ranges of the |
michael@0 | 161 | int32_t rangeHiIdx; // low and hi values currently being parsed. |
michael@0 | 162 | |
michael@0 | 163 | enum EParseState { |
michael@0 | 164 | kKeyword, |
michael@0 | 165 | kExpr, |
michael@0 | 166 | kValue, |
michael@0 | 167 | kRangeList, |
michael@0 | 168 | kSamples |
michael@0 | 169 | }; |
michael@0 | 170 | |
michael@0 | 171 | }; |
michael@0 | 172 | |
michael@0 | 173 | /** |
michael@0 | 174 | * class FixedDecimal serves to communicate the properties |
michael@0 | 175 | * of a formatted number from a decimal formatter to PluralRules::select() |
michael@0 | 176 | * |
michael@0 | 177 | * see DecimalFormat::getFixedDecimal() |
michael@0 | 178 | * @internal |
michael@0 | 179 | */ |
michael@0 | 180 | class U_I18N_API FixedDecimal: public UMemory { |
michael@0 | 181 | public: |
michael@0 | 182 | /** |
michael@0 | 183 | * @param n the number, e.g. 12.345 |
michael@0 | 184 | * @param v The number of visible fraction digits, e.g. 3 |
michael@0 | 185 | * @param f The fraction digits, e.g. 345 |
michael@0 | 186 | */ |
michael@0 | 187 | FixedDecimal(double n, int32_t v, int64_t f); |
michael@0 | 188 | FixedDecimal(double n, int32_t); |
michael@0 | 189 | explicit FixedDecimal(double n); |
michael@0 | 190 | FixedDecimal(); |
michael@0 | 191 | FixedDecimal(const UnicodeString &s, UErrorCode &ec); |
michael@0 | 192 | FixedDecimal(const FixedDecimal &other); |
michael@0 | 193 | |
michael@0 | 194 | double get(tokenType operand) const; |
michael@0 | 195 | int32_t getVisibleFractionDigitCount() const; |
michael@0 | 196 | |
michael@0 | 197 | void init(double n, int32_t v, int64_t f); |
michael@0 | 198 | void init(double n); |
michael@0 | 199 | UBool quickInit(double n); // Try a fast-path only initialization, |
michael@0 | 200 | // return TRUE if successful. |
michael@0 | 201 | void adjustForMinFractionDigits(int32_t min); |
michael@0 | 202 | static int64_t getFractionalDigits(double n, int32_t v); |
michael@0 | 203 | static int32_t decimals(double n); |
michael@0 | 204 | |
michael@0 | 205 | double source; |
michael@0 | 206 | int32_t visibleDecimalDigitCount; |
michael@0 | 207 | int64_t decimalDigits; |
michael@0 | 208 | int64_t decimalDigitsWithoutTrailingZeros; |
michael@0 | 209 | int64_t intValue; |
michael@0 | 210 | UBool hasIntegerValue; |
michael@0 | 211 | UBool isNegative; |
michael@0 | 212 | UBool isNanOrInfinity; |
michael@0 | 213 | }; |
michael@0 | 214 | |
michael@0 | 215 | class AndConstraint : public UMemory { |
michael@0 | 216 | public: |
michael@0 | 217 | typedef enum RuleOp { |
michael@0 | 218 | NONE, |
michael@0 | 219 | MOD |
michael@0 | 220 | } RuleOp; |
michael@0 | 221 | RuleOp op; |
michael@0 | 222 | int32_t opNum; // for mod expressions, the right operand of the mod. |
michael@0 | 223 | int32_t value; // valid for 'is' rules only. |
michael@0 | 224 | UVector32 *rangeList; // for 'in', 'within' rules. Null otherwise. |
michael@0 | 225 | UBool negated; // TRUE for negated rules. |
michael@0 | 226 | UBool integerOnly; // TRUE for 'within' rules. |
michael@0 | 227 | tokenType digitsType; // n | i | v | f constraint. |
michael@0 | 228 | AndConstraint *next; |
michael@0 | 229 | |
michael@0 | 230 | AndConstraint(); |
michael@0 | 231 | AndConstraint(const AndConstraint& other); |
michael@0 | 232 | virtual ~AndConstraint(); |
michael@0 | 233 | AndConstraint* add(); |
michael@0 | 234 | // UBool isFulfilled(double number); |
michael@0 | 235 | UBool isFulfilled(const FixedDecimal &number); |
michael@0 | 236 | }; |
michael@0 | 237 | |
michael@0 | 238 | class OrConstraint : public UMemory { |
michael@0 | 239 | public: |
michael@0 | 240 | AndConstraint *childNode; |
michael@0 | 241 | OrConstraint *next; |
michael@0 | 242 | OrConstraint(); |
michael@0 | 243 | |
michael@0 | 244 | OrConstraint(const OrConstraint& other); |
michael@0 | 245 | virtual ~OrConstraint(); |
michael@0 | 246 | AndConstraint* add(); |
michael@0 | 247 | // UBool isFulfilled(double number); |
michael@0 | 248 | UBool isFulfilled(const FixedDecimal &number); |
michael@0 | 249 | }; |
michael@0 | 250 | |
michael@0 | 251 | class RuleChain : public UMemory { |
michael@0 | 252 | public: |
michael@0 | 253 | UnicodeString fKeyword; |
michael@0 | 254 | RuleChain *fNext; |
michael@0 | 255 | OrConstraint *ruleHeader; |
michael@0 | 256 | UnicodeString fDecimalSamples; // Samples strings from rule source |
michael@0 | 257 | UnicodeString fIntegerSamples; // without @decimal or @integer, otherwise unprocessed. |
michael@0 | 258 | UBool fDecimalSamplesUnbounded; |
michael@0 | 259 | UBool fIntegerSamplesUnbounded; |
michael@0 | 260 | |
michael@0 | 261 | |
michael@0 | 262 | RuleChain(); |
michael@0 | 263 | RuleChain(const RuleChain& other); |
michael@0 | 264 | virtual ~RuleChain(); |
michael@0 | 265 | |
michael@0 | 266 | UnicodeString select(const FixedDecimal &number) const; |
michael@0 | 267 | void dumpRules(UnicodeString& result); |
michael@0 | 268 | UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t& arraySize) const; |
michael@0 | 269 | UBool isKeyword(const UnicodeString& keyword) const; |
michael@0 | 270 | }; |
michael@0 | 271 | |
michael@0 | 272 | class PluralKeywordEnumeration : public StringEnumeration { |
michael@0 | 273 | public: |
michael@0 | 274 | PluralKeywordEnumeration(RuleChain *header, UErrorCode& status); |
michael@0 | 275 | virtual ~PluralKeywordEnumeration(); |
michael@0 | 276 | static UClassID U_EXPORT2 getStaticClassID(void); |
michael@0 | 277 | virtual UClassID getDynamicClassID(void) const; |
michael@0 | 278 | virtual const UnicodeString* snext(UErrorCode& status); |
michael@0 | 279 | virtual void reset(UErrorCode& status); |
michael@0 | 280 | virtual int32_t count(UErrorCode& status) const; |
michael@0 | 281 | private: |
michael@0 | 282 | int32_t pos; |
michael@0 | 283 | UVector fKeywordNames; |
michael@0 | 284 | }; |
michael@0 | 285 | |
michael@0 | 286 | |
michael@0 | 287 | class U_I18N_API PluralAvailableLocalesEnumeration: public StringEnumeration { |
michael@0 | 288 | public: |
michael@0 | 289 | PluralAvailableLocalesEnumeration(UErrorCode &status); |
michael@0 | 290 | virtual ~PluralAvailableLocalesEnumeration(); |
michael@0 | 291 | virtual const char* next(int32_t *resultLength, UErrorCode& status); |
michael@0 | 292 | virtual void reset(UErrorCode& status); |
michael@0 | 293 | virtual int32_t count(UErrorCode& status) const; |
michael@0 | 294 | private: |
michael@0 | 295 | UErrorCode fOpenStatus; |
michael@0 | 296 | UResourceBundle *fLocales; |
michael@0 | 297 | UResourceBundle *fRes; |
michael@0 | 298 | }; |
michael@0 | 299 | |
michael@0 | 300 | U_NAMESPACE_END |
michael@0 | 301 | |
michael@0 | 302 | #endif /* #if !UCONFIG_NO_FORMATTING */ |
michael@0 | 303 | |
michael@0 | 304 | #endif // _PLURRULE_IMPL |
michael@0 | 305 | //eof |