michael@0: /* michael@0: ******************************************************************************* michael@0: * Copyright (C) 2007-2013, International Business Machines Corporation and michael@0: * others. All Rights Reserved. michael@0: ******************************************************************************* michael@0: * michael@0: * File PLURRULE_IMPL.H michael@0: * michael@0: ******************************************************************************* michael@0: */ michael@0: michael@0: michael@0: #ifndef PLURRULE_IMPLE michael@0: #define PLURRULE_IMPLE michael@0: michael@0: // Internal definitions for the PluralRules implementation. michael@0: michael@0: #if !UCONFIG_NO_FORMATTING michael@0: michael@0: #include "unicode/format.h" michael@0: #include "unicode/locid.h" michael@0: #include "unicode/parseerr.h" michael@0: #include "unicode/ures.h" michael@0: #include "unicode/utypes.h" michael@0: #include "uvector.h" michael@0: #include "hash.h" michael@0: michael@0: class PluralRulesTest; michael@0: michael@0: U_NAMESPACE_BEGIN michael@0: michael@0: class AndConstraint; michael@0: class RuleChain; michael@0: michael@0: static const UChar DOT = ((UChar)0x002E); michael@0: static const UChar SINGLE_QUOTE = ((UChar)0x0027); michael@0: static const UChar SLASH = ((UChar)0x002F); michael@0: static const UChar BACKSLASH = ((UChar)0x005C); michael@0: static const UChar SPACE = ((UChar)0x0020); michael@0: static const UChar EXCLAMATION = ((UChar)0x0021); michael@0: static const UChar QUOTATION_MARK = ((UChar)0x0022); michael@0: static const UChar NUMBER_SIGN = ((UChar)0x0023); michael@0: static const UChar PERCENT_SIGN = ((UChar)0x0025); michael@0: static const UChar ASTERISK = ((UChar)0x002A); michael@0: static const UChar COMMA = ((UChar)0x002C); michael@0: static const UChar HYPHEN = ((UChar)0x002D); michael@0: static const UChar U_ZERO = ((UChar)0x0030); michael@0: static const UChar U_ONE = ((UChar)0x0031); michael@0: static const UChar U_TWO = ((UChar)0x0032); michael@0: static const UChar U_THREE = ((UChar)0x0033); michael@0: static const UChar U_FOUR = ((UChar)0x0034); michael@0: static const UChar U_FIVE = ((UChar)0x0035); michael@0: static const UChar U_SIX = ((UChar)0x0036); michael@0: static const UChar U_SEVEN = ((UChar)0x0037); michael@0: static const UChar U_EIGHT = ((UChar)0x0038); michael@0: static const UChar U_NINE = ((UChar)0x0039); michael@0: static const UChar COLON = ((UChar)0x003A); michael@0: static const UChar SEMI_COLON = ((UChar)0x003B); michael@0: static const UChar EQUALS = ((UChar)0x003D); michael@0: static const UChar AT = ((UChar)0x0040); michael@0: static const UChar CAP_A = ((UChar)0x0041); michael@0: static const UChar CAP_B = ((UChar)0x0042); michael@0: static const UChar CAP_R = ((UChar)0x0052); michael@0: static const UChar CAP_Z = ((UChar)0x005A); michael@0: static const UChar LOWLINE = ((UChar)0x005F); michael@0: static const UChar LEFTBRACE = ((UChar)0x007B); michael@0: static const UChar RIGHTBRACE = ((UChar)0x007D); michael@0: static const UChar TILDE = ((UChar)0x007E); michael@0: static const UChar ELLIPSIS = ((UChar)0x2026); michael@0: michael@0: static const UChar LOW_A = ((UChar)0x0061); michael@0: static const UChar LOW_B = ((UChar)0x0062); michael@0: static const UChar LOW_C = ((UChar)0x0063); michael@0: static const UChar LOW_D = ((UChar)0x0064); michael@0: static const UChar LOW_E = ((UChar)0x0065); michael@0: static const UChar LOW_F = ((UChar)0x0066); michael@0: static const UChar LOW_G = ((UChar)0x0067); michael@0: static const UChar LOW_H = ((UChar)0x0068); michael@0: static const UChar LOW_I = ((UChar)0x0069); michael@0: static const UChar LOW_J = ((UChar)0x006a); michael@0: static const UChar LOW_K = ((UChar)0x006B); michael@0: static const UChar LOW_L = ((UChar)0x006C); michael@0: static const UChar LOW_M = ((UChar)0x006D); michael@0: static const UChar LOW_N = ((UChar)0x006E); michael@0: static const UChar LOW_O = ((UChar)0x006F); michael@0: static const UChar LOW_P = ((UChar)0x0070); michael@0: static const UChar LOW_Q = ((UChar)0x0071); michael@0: static const UChar LOW_R = ((UChar)0x0072); michael@0: static const UChar LOW_S = ((UChar)0x0073); michael@0: static const UChar LOW_T = ((UChar)0x0074); michael@0: static const UChar LOW_U = ((UChar)0x0075); michael@0: static const UChar LOW_V = ((UChar)0x0076); michael@0: static const UChar LOW_W = ((UChar)0x0077); michael@0: static const UChar LOW_Y = ((UChar)0x0079); michael@0: static const UChar LOW_Z = ((UChar)0x007A); michael@0: michael@0: michael@0: static const int32_t PLURAL_RANGE_HIGH = 0x7fffffff; michael@0: michael@0: enum tokenType { michael@0: none, michael@0: tNumber, michael@0: tComma, michael@0: tSemiColon, michael@0: tSpace, michael@0: tColon, michael@0: tAt, // '@' michael@0: tDot, michael@0: tDot2, michael@0: tEllipsis, michael@0: tKeyword, michael@0: tAnd, michael@0: tOr, michael@0: tMod, // 'mod' or '%' michael@0: tNot, // 'not' only. michael@0: tIn, // 'in' only. michael@0: tEqual, // '=' only. michael@0: tNotEqual, // '!=' michael@0: tTilde, michael@0: tWithin, michael@0: tIs, michael@0: tVariableN, michael@0: tVariableI, michael@0: tVariableF, michael@0: tVariableV, michael@0: tVariableT, michael@0: tDecimal, michael@0: tInteger, michael@0: tEOF michael@0: }; michael@0: michael@0: michael@0: class PluralRuleParser: public UMemory { michael@0: public: michael@0: PluralRuleParser(); michael@0: virtual ~PluralRuleParser(); michael@0: michael@0: void parse(const UnicodeString &rules, PluralRules *dest, UErrorCode &status); michael@0: void getNextToken(UErrorCode &status); michael@0: void checkSyntax(UErrorCode &status); michael@0: static int32_t getNumberValue(const UnicodeString &token); michael@0: michael@0: private: michael@0: static tokenType getKeyType(const UnicodeString& token, tokenType type); michael@0: static tokenType charType(UChar ch); michael@0: static UBool isValidKeyword(const UnicodeString& token); michael@0: michael@0: const UnicodeString *ruleSrc; // The rules string. michael@0: int32_t ruleIndex; // String index in the input rules, the current parse position. michael@0: UnicodeString token; // Token most recently scanned. michael@0: tokenType type; michael@0: tokenType prevType; michael@0: michael@0: // The items currently being parsed & built. michael@0: // Note: currentChain may not be the last RuleChain in the michael@0: // list because the "other" chain is forced to the end. michael@0: AndConstraint *curAndConstraint; michael@0: RuleChain *currentChain; michael@0: michael@0: int32_t rangeLowIdx; // Indices in the UVector of ranges of the michael@0: int32_t rangeHiIdx; // low and hi values currently being parsed. michael@0: michael@0: enum EParseState { michael@0: kKeyword, michael@0: kExpr, michael@0: kValue, michael@0: kRangeList, michael@0: kSamples michael@0: }; michael@0: michael@0: }; michael@0: michael@0: /** michael@0: * class FixedDecimal serves to communicate the properties michael@0: * of a formatted number from a decimal formatter to PluralRules::select() michael@0: * michael@0: * see DecimalFormat::getFixedDecimal() michael@0: * @internal michael@0: */ michael@0: class U_I18N_API FixedDecimal: public UMemory { michael@0: public: michael@0: /** michael@0: * @param n the number, e.g. 12.345 michael@0: * @param v The number of visible fraction digits, e.g. 3 michael@0: * @param f The fraction digits, e.g. 345 michael@0: */ michael@0: FixedDecimal(double n, int32_t v, int64_t f); michael@0: FixedDecimal(double n, int32_t); michael@0: explicit FixedDecimal(double n); michael@0: FixedDecimal(); michael@0: FixedDecimal(const UnicodeString &s, UErrorCode &ec); michael@0: FixedDecimal(const FixedDecimal &other); michael@0: michael@0: double get(tokenType operand) const; michael@0: int32_t getVisibleFractionDigitCount() const; michael@0: michael@0: void init(double n, int32_t v, int64_t f); michael@0: void init(double n); michael@0: UBool quickInit(double n); // Try a fast-path only initialization, michael@0: // return TRUE if successful. michael@0: void adjustForMinFractionDigits(int32_t min); michael@0: static int64_t getFractionalDigits(double n, int32_t v); michael@0: static int32_t decimals(double n); michael@0: michael@0: double source; michael@0: int32_t visibleDecimalDigitCount; michael@0: int64_t decimalDigits; michael@0: int64_t decimalDigitsWithoutTrailingZeros; michael@0: int64_t intValue; michael@0: UBool hasIntegerValue; michael@0: UBool isNegative; michael@0: UBool isNanOrInfinity; michael@0: }; michael@0: michael@0: class AndConstraint : public UMemory { michael@0: public: michael@0: typedef enum RuleOp { michael@0: NONE, michael@0: MOD michael@0: } RuleOp; michael@0: RuleOp op; michael@0: int32_t opNum; // for mod expressions, the right operand of the mod. michael@0: int32_t value; // valid for 'is' rules only. michael@0: UVector32 *rangeList; // for 'in', 'within' rules. Null otherwise. michael@0: UBool negated; // TRUE for negated rules. michael@0: UBool integerOnly; // TRUE for 'within' rules. michael@0: tokenType digitsType; // n | i | v | f constraint. michael@0: AndConstraint *next; michael@0: michael@0: AndConstraint(); michael@0: AndConstraint(const AndConstraint& other); michael@0: virtual ~AndConstraint(); michael@0: AndConstraint* add(); michael@0: // UBool isFulfilled(double number); michael@0: UBool isFulfilled(const FixedDecimal &number); michael@0: }; michael@0: michael@0: class OrConstraint : public UMemory { michael@0: public: michael@0: AndConstraint *childNode; michael@0: OrConstraint *next; michael@0: OrConstraint(); michael@0: michael@0: OrConstraint(const OrConstraint& other); michael@0: virtual ~OrConstraint(); michael@0: AndConstraint* add(); michael@0: // UBool isFulfilled(double number); michael@0: UBool isFulfilled(const FixedDecimal &number); michael@0: }; michael@0: michael@0: class RuleChain : public UMemory { michael@0: public: michael@0: UnicodeString fKeyword; michael@0: RuleChain *fNext; michael@0: OrConstraint *ruleHeader; michael@0: UnicodeString fDecimalSamples; // Samples strings from rule source michael@0: UnicodeString fIntegerSamples; // without @decimal or @integer, otherwise unprocessed. michael@0: UBool fDecimalSamplesUnbounded; michael@0: UBool fIntegerSamplesUnbounded; michael@0: michael@0: michael@0: RuleChain(); michael@0: RuleChain(const RuleChain& other); michael@0: virtual ~RuleChain(); michael@0: michael@0: UnicodeString select(const FixedDecimal &number) const; michael@0: void dumpRules(UnicodeString& result); michael@0: UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t& arraySize) const; michael@0: UBool isKeyword(const UnicodeString& keyword) const; michael@0: }; michael@0: michael@0: class PluralKeywordEnumeration : public StringEnumeration { michael@0: public: michael@0: PluralKeywordEnumeration(RuleChain *header, UErrorCode& status); michael@0: virtual ~PluralKeywordEnumeration(); michael@0: static UClassID U_EXPORT2 getStaticClassID(void); michael@0: virtual UClassID getDynamicClassID(void) const; michael@0: virtual const UnicodeString* snext(UErrorCode& status); michael@0: virtual void reset(UErrorCode& status); michael@0: virtual int32_t count(UErrorCode& status) const; michael@0: private: michael@0: int32_t pos; michael@0: UVector fKeywordNames; michael@0: }; michael@0: michael@0: michael@0: class U_I18N_API PluralAvailableLocalesEnumeration: public StringEnumeration { michael@0: public: michael@0: PluralAvailableLocalesEnumeration(UErrorCode &status); michael@0: virtual ~PluralAvailableLocalesEnumeration(); michael@0: virtual const char* next(int32_t *resultLength, UErrorCode& status); michael@0: virtual void reset(UErrorCode& status); michael@0: virtual int32_t count(UErrorCode& status) const; michael@0: private: michael@0: UErrorCode fOpenStatus; michael@0: UResourceBundle *fLocales; michael@0: UResourceBundle *fRes; michael@0: }; michael@0: michael@0: U_NAMESPACE_END michael@0: michael@0: #endif /* #if !UCONFIG_NO_FORMATTING */ michael@0: michael@0: #endif // _PLURRULE_IMPL michael@0: //eof