| // © 2018 and later: Unicode, Inc. and others. | 
 | // License & terms of use: http://www.unicode.org/copyright.html | 
 |  | 
 | #include "unicode/utypes.h" | 
 |  | 
 | #if !UCONFIG_NO_FORMATTING | 
 |  | 
 | // Allow implicit conversion from char16_t* to UnicodeString for this file: | 
 | // Helpful in toString methods and elsewhere. | 
 | #define UNISTR_FROM_STRING_EXPLICIT | 
 |  | 
 | #include "numparse_types.h" | 
 | #include "numparse_symbols.h" | 
 | #include "numparse_utils.h" | 
 | #include "string_segment.h" | 
 |  | 
 | using namespace icu; | 
 | using namespace icu::numparse; | 
 | using namespace icu::numparse::impl; | 
 |  | 
 |  | 
 | SymbolMatcher::SymbolMatcher(const UnicodeString& symbolString, unisets::Key key) { | 
 |     fUniSet = unisets::get(key); | 
 |     if (fUniSet->contains(symbolString)) { | 
 |         fString.setToBogus(); | 
 |     } else { | 
 |         fString = symbolString; | 
 |     } | 
 | } | 
 |  | 
 | const UnicodeSet* SymbolMatcher::getSet() const { | 
 |     return fUniSet; | 
 | } | 
 |  | 
 | bool SymbolMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode&) const { | 
 |     // Smoke test first; this matcher might be disabled. | 
 |     if (isDisabled(result)) { | 
 |         return false; | 
 |     } | 
 |  | 
 |     // Test the string first in order to consume trailing chars greedily. | 
 |     int overlap = 0; | 
 |     if (!fString.isEmpty()) { | 
 |         overlap = segment.getCommonPrefixLength(fString); | 
 |         if (overlap == fString.length()) { | 
 |             segment.adjustOffset(fString.length()); | 
 |             accept(segment, result); | 
 |             return false; | 
 |         } | 
 |     } | 
 |  | 
 |     int cp = segment.getCodePoint(); | 
 |     if (cp != -1 && fUniSet->contains(cp)) { | 
 |         segment.adjustOffset(U16_LENGTH(cp)); | 
 |         accept(segment, result); | 
 |         return false; | 
 |     } | 
 |  | 
 |     return overlap == segment.length(); | 
 | } | 
 |  | 
 | bool SymbolMatcher::smokeTest(const StringSegment& segment) const { | 
 |     return segment.startsWith(*fUniSet) || segment.startsWith(fString); | 
 | } | 
 |  | 
 | UnicodeString SymbolMatcher::toString() const { | 
 |     // TODO: Customize output for each symbol | 
 |     return u"<Symbol>"; | 
 | } | 
 |  | 
 |  | 
 | IgnorablesMatcher::IgnorablesMatcher(parse_flags_t parseFlags) : | 
 |         SymbolMatcher( | 
 |             {}, | 
 |             (0 != (parseFlags & PARSE_FLAG_STRICT_IGNORABLES)) ? | 
 |                 unisets::STRICT_IGNORABLES : | 
 |                 unisets::DEFAULT_IGNORABLES) { | 
 | } | 
 |  | 
 | bool IgnorablesMatcher::isFlexible() const { | 
 |     return true; | 
 | } | 
 |  | 
 | UnicodeString IgnorablesMatcher::toString() const { | 
 |     return u"<Ignorables>"; | 
 | } | 
 |  | 
 | bool IgnorablesMatcher::isDisabled(const ParsedNumber&) const { | 
 |     return false; | 
 | } | 
 |  | 
 | void IgnorablesMatcher::accept(StringSegment&, ParsedNumber&) const { | 
 |     // No-op | 
 | } | 
 |  | 
 |  | 
 | InfinityMatcher::InfinityMatcher(const DecimalFormatSymbols& dfs) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), unisets::INFINITY_SIGN) { | 
 | } | 
 |  | 
 | bool InfinityMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return 0 != (result.flags & FLAG_INFINITY); | 
 | } | 
 |  | 
 | void InfinityMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.flags |= FLAG_INFINITY; | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | MinusSignMatcher::MinusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol), unisets::MINUS_SIGN), | 
 |           fAllowTrailing(allowTrailing) { | 
 | } | 
 |  | 
 | bool MinusSignMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return !fAllowTrailing && result.seenNumber(); | 
 | } | 
 |  | 
 | void MinusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.flags |= FLAG_NEGATIVE; | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | NanMatcher::NanMatcher(const DecimalFormatSymbols& dfs) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), unisets::EMPTY) { | 
 | } | 
 |  | 
 | bool NanMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return result.seenNumber(); | 
 | } | 
 |  | 
 | void NanMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.flags |= FLAG_NAN; | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | PaddingMatcher::PaddingMatcher(const UnicodeString& padString) | 
 |         : SymbolMatcher(padString, unisets::EMPTY) {} | 
 |  | 
 | bool PaddingMatcher::isFlexible() const { | 
 |     return true; | 
 | } | 
 |  | 
 | bool PaddingMatcher::isDisabled(const ParsedNumber&) const { | 
 |     return false; | 
 | } | 
 |  | 
 | void PaddingMatcher::accept(StringSegment&, ParsedNumber&) const { | 
 |     // No-op | 
 | } | 
 |  | 
 |  | 
 | PercentMatcher::PercentMatcher(const DecimalFormatSymbols& dfs) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPercentSymbol), unisets::PERCENT_SIGN) { | 
 | } | 
 |  | 
 | bool PercentMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return 0 != (result.flags & FLAG_PERCENT); | 
 | } | 
 |  | 
 | void PercentMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.flags |= FLAG_PERCENT; | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | PermilleMatcher::PermilleMatcher(const DecimalFormatSymbols& dfs) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPerMillSymbol), unisets::PERMILLE_SIGN) { | 
 | } | 
 |  | 
 | bool PermilleMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return 0 != (result.flags & FLAG_PERMILLE); | 
 | } | 
 |  | 
 | void PermilleMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.flags |= FLAG_PERMILLE; | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | PlusSignMatcher::PlusSignMatcher(const DecimalFormatSymbols& dfs, bool allowTrailing) | 
 |         : SymbolMatcher(dfs.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol), unisets::PLUS_SIGN), | 
 |           fAllowTrailing(allowTrailing) { | 
 | } | 
 |  | 
 | bool PlusSignMatcher::isDisabled(const ParsedNumber& result) const { | 
 |     return !fAllowTrailing && result.seenNumber(); | 
 | } | 
 |  | 
 | void PlusSignMatcher::accept(StringSegment& segment, ParsedNumber& result) const { | 
 |     result.setCharsConsumed(segment); | 
 | } | 
 |  | 
 |  | 
 | #endif /* #if !UCONFIG_NO_FORMATTING */ |