]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/number_skeletons.cpp
ICU-64232.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / number_skeletons.cpp
index c7bb18b5f3d2b5130bcebf17ffa9d8caecd1360c..6dbcb1360cb3231ff4a410a8471de94e67bc1044 100644 (file)
@@ -159,8 +159,7 @@ Notation stem_to_object::notation(skeleton::StemEnum stem) {
         case STEM_NOTATION_SIMPLE:
             return Notation::simple();
         default:
-            U_ASSERT(false);
-            return Notation::simple(); // return a value: silence compiler warning
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -176,8 +175,7 @@ MeasureUnit stem_to_object::unit(skeleton::StemEnum stem) {
             // Slicing is okay
             return NoUnit::permille(); // NOLINT
         default:
-            U_ASSERT(false);
-            return {}; // return a value: silence compiler warning
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -192,8 +190,7 @@ Precision stem_to_object::precision(skeleton::StemEnum stem) {
         case STEM_PRECISION_CURRENCY_CASH:
             return Precision::currency(UCURR_USAGE_CASH);
         default:
-            U_ASSERT(false);
-            return Precision::integer(); // return a value: silence compiler warning
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -216,12 +213,11 @@ UNumberFormatRoundingMode stem_to_object::roundingMode(skeleton::StemEnum stem)
         case STEM_ROUNDING_MODE_UNNECESSARY:
             return UNUM_ROUND_UNNECESSARY;
         default:
-            U_ASSERT(false);
-            return UNUM_ROUND_UNNECESSARY;
+            UPRV_UNREACHABLE;
     }
 }
 
-UGroupingStrategy stem_to_object::groupingStrategy(skeleton::StemEnum stem) {
+UNumberGroupingStrategy stem_to_object::groupingStrategy(skeleton::StemEnum stem) {
     switch (stem) {
         case STEM_GROUP_OFF:
             return UNUM_GROUPING_OFF;
@@ -315,11 +311,11 @@ void enum_to_stem_string::roundingMode(UNumberFormatRoundingMode value, UnicodeS
             sb.append(u"rounding-mode-unnecessary", -1);
             break;
         default:
-            U_ASSERT(false);
+            UPRV_UNREACHABLE;
     }
 }
 
-void enum_to_stem_string::groupingStrategy(UGroupingStrategy value, UnicodeString& sb) {
+void enum_to_stem_string::groupingStrategy(UNumberGroupingStrategy value, UnicodeString& sb) {
     switch (value) {
         case UNUM_GROUPING_OFF:
             sb.append(u"group-off", -1);
@@ -337,7 +333,7 @@ void enum_to_stem_string::groupingStrategy(UGroupingStrategy value, UnicodeStrin
             sb.append(u"group-thousands", -1);
             break;
         default:
-            U_ASSERT(false);
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -359,7 +355,7 @@ void enum_to_stem_string::unitWidth(UNumberUnitWidth value, UnicodeString& sb) {
             sb.append(u"unit-width-hidden", -1);
             break;
         default:
-            U_ASSERT(false);
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -387,7 +383,7 @@ void enum_to_stem_string::signDisplay(UNumberSignDisplay value, UnicodeString& s
             sb.append(u"sign-accounting-except-zero", -1);
             break;
         default:
-            U_ASSERT(false);
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -401,15 +397,46 @@ enum_to_stem_string::decimalSeparatorDisplay(UNumberDecimalSeparatorDisplay valu
             sb.append(u"decimal-always", -1);
             break;
         default:
-            U_ASSERT(false);
+            UPRV_UNREACHABLE;
     }
 }
 
 
-UnlocalizedNumberFormatter skeleton::create(const UnicodeString& skeletonString, UErrorCode& status) {
+UnlocalizedNumberFormatter skeleton::create(
+        const UnicodeString& skeletonString, UParseError* perror, UErrorCode& status) {
+
+    // Initialize perror
+    if (perror != nullptr) {
+        perror->line = 0;
+        perror->offset = -1;
+        perror->preContext[0] = 0;
+        perror->postContext[0] = 0;
+    }
+
     umtx_initOnce(gNumberSkeletonsInitOnce, &initNumberSkeletons, status);
-    MacroProps macros = parseSkeleton(skeletonString, status);
-    return NumberFormatter::with().macros(macros);
+    if (U_FAILURE(status)) {
+        return {};
+    }
+
+    int32_t errOffset;
+    MacroProps macros = parseSkeleton(skeletonString, errOffset, status);
+    if (U_SUCCESS(status)) {
+        return NumberFormatter::with().macros(macros);
+    }
+
+    if (perror == nullptr) {
+        return {};
+    }
+
+    // Populate the UParseError with the error location
+    perror->offset = errOffset;
+    int32_t contextStart = uprv_max(0, errOffset - U_PARSE_CONTEXT_LEN + 1);
+    int32_t contextEnd = uprv_min(skeletonString.length(), errOffset + U_PARSE_CONTEXT_LEN - 1);
+    skeletonString.extract(contextStart, errOffset - contextStart, perror->preContext, 0);
+    perror->preContext[errOffset - contextStart] = 0;
+    skeletonString.extract(errOffset, contextEnd - errOffset, perror->postContext, 0);
+    perror->postContext[contextEnd - errOffset] = 0;
+    return {};
 }
 
 UnicodeString skeleton::generate(const MacroProps& macros, UErrorCode& status) {
@@ -419,8 +446,9 @@ UnicodeString skeleton::generate(const MacroProps& macros, UErrorCode& status) {
     return sb;
 }
 
-MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCode& status) {
-    if (U_FAILURE(status)) { return MacroProps(); }
+MacroProps skeleton::parseSkeleton(
+        const UnicodeString& skeletonString, int32_t& errOffset, UErrorCode& status) {
+    U_ASSERT(U_SUCCESS(status));
 
     // Add a trailing whitespace to the end of the skeleton string to make code cleaner.
     UnicodeString tempSkeletonString(skeletonString);
@@ -464,7 +492,10 @@ MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCo
                 stem = parseOption(stem, segment, macros, status);
             }
             segment.resetLength();
-            if (U_FAILURE(status)) { return macros; }
+            if (U_FAILURE(status)) {
+                errOffset = segment.getOffset();
+                return macros;
+            }
 
             // Consume the segment:
             segment.adjustOffset(offset);
@@ -475,6 +506,7 @@ MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCo
             // segment.setLength(U16_LENGTH(cp)); // for error message
             // throw new SkeletonSyntaxException("Unexpected separator character", segment);
             status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+            errOffset = segment.getOffset();
             return macros;
 
         } else {
@@ -486,6 +518,7 @@ MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCo
             // segment.setLength(U16_LENGTH(cp)); // for error message
             // throw new SkeletonSyntaxException("Unexpected option separator", segment);
             status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+            errOffset = segment.getOffset();
             return macros;
         }
 
@@ -502,6 +535,7 @@ MacroProps skeleton::parseSkeleton(const UnicodeString& skeletonString, UErrorCo
                     // segment.setLength(U16_LENGTH(cp)); // for error message
                     // throw new SkeletonSyntaxException("Stem requires an option", segment);
                     status = U_NUMBER_SKELETON_SYNTAX_ERROR;
+                    errOffset = segment.getOffset();
                     return macros;
                 default:
                     break;
@@ -665,8 +699,7 @@ skeleton::parseStem(const StringSegment& segment, const UCharsTrie& stemTrie, Se
             return STATE_SCALE;
 
         default:
-            U_ASSERT(false);
-            return STATE_NULL; // return a value: silence compiler warning
+            UPRV_UNREACHABLE;
     }
 }
 
@@ -1380,6 +1413,9 @@ bool GeneratorHelpers::precision(const MacroProps& macros, UnicodeString& sb, UE
     } else if (macros.precision.fType == Precision::RND_SIGNIFICANT) {
         const Precision::FractionSignificantSettings& impl = macros.precision.fUnion.fracSig;
         blueprint_helpers::generateDigitsStem(impl.fMinSig, impl.fMaxSig, sb, status);
+    } else if (macros.precision.fType == Precision::RND_INCREMENT_SIGNIFICANT) { // Apple rdar://52538227
+        const Precision::IncrementSignificantSettings& impl = macros.precision.fUnion.incrSig;
+        blueprint_helpers::generateDigitsStem(impl.fMinSig, impl.fMaxSig, sb, status);
     } else if (macros.precision.fType == Precision::RND_FRACTION_SIGNIFICANT) {
         const Precision::FractionSignificantSettings& impl = macros.precision.fUnion.fracSig;
         blueprint_helpers::generateFractionStem(impl.fMinFrac, impl.fMaxFrac, sb, status);
@@ -1389,7 +1425,9 @@ bool GeneratorHelpers::precision(const MacroProps& macros, UnicodeString& sb, UE
         } else {
             blueprint_helpers::generateDigitsStem(impl.fMinSig, -1, sb, status);
         }
-    } else if (macros.precision.fType == Precision::RND_INCREMENT) {
+    } else if (macros.precision.fType == Precision::RND_INCREMENT
+            || macros.precision.fType == Precision::RND_INCREMENT_ONE
+            || macros.precision.fType == Precision::RND_INCREMENT_FIVE) {
         const Precision::IncrementSettings& impl = macros.precision.fUnion.increment;
         sb.append(u"precision-increment/", -1);
         blueprint_helpers::generateIncrementOption(