11cb0ef41Sopenharmony_ci// © 2018 and later: Unicode, Inc. and others.
21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#include "unicode/utypes.h"
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ci#if !UCONFIG_NO_FORMATTING
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ci// Allow implicit conversion from char16_t* to UnicodeString for this file:
91cb0ef41Sopenharmony_ci// Helpful in toString methods and elsewhere.
101cb0ef41Sopenharmony_ci#define UNISTR_FROM_STRING_EXPLICIT
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci#include "numparse_types.h"
131cb0ef41Sopenharmony_ci#include "numparse_compositions.h"
141cb0ef41Sopenharmony_ci#include "string_segment.h"
151cb0ef41Sopenharmony_ci#include "unicode/uniset.h"
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ciusing namespace icu;
181cb0ef41Sopenharmony_ciusing namespace icu::numparse;
191cb0ef41Sopenharmony_ciusing namespace icu::numparse::impl;
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_cibool SeriesMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& status) const {
231cb0ef41Sopenharmony_ci    ParsedNumber backup(result);
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_ci    int32_t initialOffset = segment.getOffset();
261cb0ef41Sopenharmony_ci    bool maybeMore = true;
271cb0ef41Sopenharmony_ci    for (auto* it = begin(); it < end();) {
281cb0ef41Sopenharmony_ci        const NumberParseMatcher* matcher = *it;
291cb0ef41Sopenharmony_ci        int matcherOffset = segment.getOffset();
301cb0ef41Sopenharmony_ci        if (segment.length() != 0) {
311cb0ef41Sopenharmony_ci            maybeMore = matcher->match(segment, result, status);
321cb0ef41Sopenharmony_ci        } else {
331cb0ef41Sopenharmony_ci            // Nothing for this matcher to match; ask for more.
341cb0ef41Sopenharmony_ci            maybeMore = true;
351cb0ef41Sopenharmony_ci        }
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_ci        bool success = (segment.getOffset() != matcherOffset);
381cb0ef41Sopenharmony_ci        bool isFlexible = matcher->isFlexible();
391cb0ef41Sopenharmony_ci        if (success && isFlexible) {
401cb0ef41Sopenharmony_ci            // Match succeeded, and this is a flexible matcher. Re-run it.
411cb0ef41Sopenharmony_ci        } else if (success) {
421cb0ef41Sopenharmony_ci            // Match succeeded, and this is NOT a flexible matcher. Proceed to the next matcher.
431cb0ef41Sopenharmony_ci            it++;
441cb0ef41Sopenharmony_ci            // Small hack: if there is another matcher coming, do not accept trailing weak chars.
451cb0ef41Sopenharmony_ci            // Needed for proper handling of currency spacing.
461cb0ef41Sopenharmony_ci            if (it < end() && segment.getOffset() != result.charEnd && result.charEnd > matcherOffset) {
471cb0ef41Sopenharmony_ci                segment.setOffset(result.charEnd);
481cb0ef41Sopenharmony_ci            }
491cb0ef41Sopenharmony_ci        } else if (isFlexible) {
501cb0ef41Sopenharmony_ci            // Match failed, and this is a flexible matcher. Try again with the next matcher.
511cb0ef41Sopenharmony_ci            it++;
521cb0ef41Sopenharmony_ci        } else {
531cb0ef41Sopenharmony_ci            // Match failed, and this is NOT a flexible matcher. Exit.
541cb0ef41Sopenharmony_ci            segment.setOffset(initialOffset);
551cb0ef41Sopenharmony_ci            result = backup;
561cb0ef41Sopenharmony_ci            return maybeMore;
571cb0ef41Sopenharmony_ci        }
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci    // All matchers in the series succeeded.
611cb0ef41Sopenharmony_ci    return maybeMore;
621cb0ef41Sopenharmony_ci}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_cibool SeriesMatcher::smokeTest(const StringSegment& segment) const {
651cb0ef41Sopenharmony_ci    // NOTE: The range-based for loop calls the virtual begin() and end() methods.
661cb0ef41Sopenharmony_ci    // NOTE: We only want the first element. Use the for loop for boundary checking.
671cb0ef41Sopenharmony_ci    for (auto& matcher : *this) {
681cb0ef41Sopenharmony_ci        // SeriesMatchers are never allowed to start with a Flexible matcher.
691cb0ef41Sopenharmony_ci        U_ASSERT(!matcher->isFlexible());
701cb0ef41Sopenharmony_ci        return matcher->smokeTest(segment);
711cb0ef41Sopenharmony_ci    }
721cb0ef41Sopenharmony_ci    return false;
731cb0ef41Sopenharmony_ci}
741cb0ef41Sopenharmony_ci
751cb0ef41Sopenharmony_civoid SeriesMatcher::postProcess(ParsedNumber& result) const {
761cb0ef41Sopenharmony_ci    // NOTE: The range-based for loop calls the virtual begin() and end() methods.
771cb0ef41Sopenharmony_ci    for (auto* matcher : *this) {
781cb0ef41Sopenharmony_ci        matcher->postProcess(result);
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci}
811cb0ef41Sopenharmony_ci
821cb0ef41Sopenharmony_ci
831cb0ef41Sopenharmony_ciArraySeriesMatcher::ArraySeriesMatcher()
841cb0ef41Sopenharmony_ci        : fMatchersLen(0) {
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ciArraySeriesMatcher::ArraySeriesMatcher(MatcherArray& matchers, int32_t matchersLen)
881cb0ef41Sopenharmony_ci        : fMatchers(std::move(matchers)), fMatchersLen(matchersLen) {
891cb0ef41Sopenharmony_ci}
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ciint32_t ArraySeriesMatcher::length() const {
921cb0ef41Sopenharmony_ci    return fMatchersLen;
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ciconst NumberParseMatcher* const* ArraySeriesMatcher::begin() const {
961cb0ef41Sopenharmony_ci    return fMatchers.getAlias();
971cb0ef41Sopenharmony_ci}
981cb0ef41Sopenharmony_ci
991cb0ef41Sopenharmony_ciconst NumberParseMatcher* const* ArraySeriesMatcher::end() const {
1001cb0ef41Sopenharmony_ci    return fMatchers.getAlias() + fMatchersLen;
1011cb0ef41Sopenharmony_ci}
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ciUnicodeString ArraySeriesMatcher::toString() const {
1041cb0ef41Sopenharmony_ci    return u"<ArraySeries>";
1051cb0ef41Sopenharmony_ci}
1061cb0ef41Sopenharmony_ci
1071cb0ef41Sopenharmony_ci
1081cb0ef41Sopenharmony_ci#endif /* #if !UCONFIG_NO_FORMATTING */
109