Skip to content

Commit

Permalink
ICU-13513 Down to line 916 in the data-driven test file.
Browse files Browse the repository at this point in the history
X-SVN-Rev: 40734
  • Loading branch information
sffc committed Dec 14, 2017
1 parent a0de8d8 commit 68340c8
Show file tree
Hide file tree
Showing 17 changed files with 270 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public interface DecimalQuantity extends PluralRules.IFixedDecimal {
*/
public void roundToInfinity();

/**
* Truncates the decimals from this DecimalQuantity. Equivalent to calling roundToMagnitude(0, FLOOR)
*/
void truncate();

/**
* Multiply the internal value.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,15 @@ public void roundToInfinity() {
}
}

@Override
public void truncate() {
if (scale < 0) {
shiftRight(-scale);
scale = 0;
compact();
}
}

/**
* Appends a digit, optionally with one or more leading zeros, to the end of the value represented
* by this DecimalQuantity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.parse;

import java.util.Collection;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
Expand Down Expand Up @@ -47,6 +48,7 @@ public int compare(AffixMatcher o1, AffixMatcher o2) {
public static void generateFromPatternModifier(
MutablePatternModifier patternModifier,
int flags,
boolean includeUnpaired,
NumberParserImpl output) {

// Store the matchers in a TreeSet to ensure both uniqueness and order.
Expand All @@ -64,11 +66,11 @@ public static void generateFromPatternModifier(
if (patternModifier.needsPlurals()) {
for (StandardPlural plural : StandardPlural.VALUES) {
patternModifier.setNumberProperties(isNegative, plural);
matchers.add(getInstance(patternModifier, flags, nsb));
AffixMatcher.createAndAppendTo(matchers, patternModifier, flags, nsb, includeUnpaired);
}
} else {
patternModifier.setNumberProperties(isNegative, null);
matchers.add(getInstance(patternModifier, flags, nsb));
AffixMatcher.createAndAppendTo(matchers, patternModifier, flags, nsb, includeUnpaired);
}

if (isNegative) {
Expand All @@ -84,21 +86,29 @@ public static void generateFromPatternModifier(
}

/**
* Constructs an AffixMatcher from the given MutablePatternModifier and flags. The NumberStringBuilder is used as a
* temporary object only.
* Constructs one or more AffixMatchers from the given MutablePatternModifier and flags, appending them to the given
* collection. The NumberStringBuilder is used as a temporary object only.
*
* @param includeUnpaired If true, create additional AffixMatchers with an unpaired prefix or suffix.
*/
private static AffixMatcher getInstance(
private static void createAndAppendTo(
Collection<AffixMatcher> appendTo,
MutablePatternModifier patternModifier,
int flags,
NumberStringBuilder nsb) {
NumberStringBuilder nsb,
boolean includeUnpaired) {
// TODO: Make this more efficient (avoid the substrings and things)
nsb.clear();
patternModifier.apply(nsb, 0, 0);
int prefixLength = patternModifier.getPrefixLength();
String full = nsb.toString();
String prefix = full.substring(0, prefixLength);
String suffix = full.substring(prefixLength);
return new AffixMatcher(prefix, suffix, flags);
appendTo.add(new AffixMatcher(prefix, suffix, flags));
if (includeUnpaired && !prefix.isEmpty() && !suffix.isEmpty()) {
appendTo.add(new AffixMatcher(prefix, "", flags));
appendTo.add(new AffixMatcher("", suffix, flags));
}
}

private AffixMatcher(String prefix, String suffix, int flags) {
Expand Down Expand Up @@ -147,6 +157,10 @@ public boolean match(StringSegment segment, ParsedNumber result) {
public void postProcess(ParsedNumber result) {
// Check to see if our affix is the one that was matched. If so, set the flags in the result.
if (prefix.equals(orEmpty(result.prefix)) && suffix.equals(orEmpty(result.suffix))) {
// Fill in the result prefix and suffix with non-null values (empty string).
// Used by strict mode to determine whether an entire affix pair was matched.
result.prefix = prefix;
result.suffix = suffix;
result.flags |= flags;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// License & terms of use: http://www.unicode.org/copyright.html#License
package com.ibm.icu.impl.number.parse;

import java.math.RoundingMode;

import com.ibm.icu.impl.number.DecimalQuantity_DualStorageBCD;
import com.ibm.icu.impl.number.RoundingUtils;
import com.ibm.icu.lang.UCharacter;
import com.ibm.icu.text.DecimalFormatSymbols;
import com.ibm.icu.text.UnicodeSet;
Expand All @@ -30,8 +27,10 @@ public class DecimalMatcher implements NumberParseMatcher {

public static DecimalMatcher getInstance(DecimalFormatSymbols symbols) {
String groupingSeparator = symbols.getGroupingSeparatorString();
UnicodeSet groupingSet = UNISET_COMMA_LIKE.contains(groupingSeparator) ? UNISET_COMMA_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
: UNISET_PERIOD_LIKE.contains(groupingSeparator) ? UNISET_PERIOD_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
UnicodeSet groupingSet = UNISET_COMMA_LIKE.contains(groupingSeparator)
? UNISET_COMMA_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
: UNISET_PERIOD_LIKE.contains(groupingSeparator)
? UNISET_PERIOD_LIKE.cloneAsThawed().addAll(UNISET_OTHER_GROUPING_SEPARATORS).freeze()
: UNISET_OTHER_GROUPING_SEPARATORS.contains(groupingSeparator)
? UNISET_OTHER_GROUPING_SEPARATORS
: new UnicodeSet().addAll(groupingSeparator).freeze();
Expand All @@ -45,8 +44,10 @@ public static DecimalMatcher getInstance(DecimalFormatSymbols symbols) {
}

public static DecimalMatcher getExponentInstance(DecimalFormatSymbols symbols) {
return new DecimalMatcher(symbols
.getDigitStrings(), new UnicodeSet("[,]").freeze(), new UnicodeSet("[.]").freeze(), true);
return new DecimalMatcher(symbols.getDigitStrings(),
new UnicodeSet("[,]").freeze(),
new UnicodeSet("[.]").freeze(),
true);
}

private final String[] digitStrings;
Expand All @@ -55,8 +56,9 @@ public static DecimalMatcher getExponentInstance(DecimalFormatSymbols symbols) {
private final UnicodeSet separatorSet;
public boolean requireGroupingMatch = false;
public boolean groupingEnabled = true;
private final int grouping1 = 3;
private final int grouping2 = 3;
public int grouping1 = 3;
public int grouping2 = 3;
public boolean integerOnly = false;
private final boolean isScientific;

private DecimalMatcher(
Expand All @@ -82,10 +84,11 @@ public boolean match(StringSegment segment, ParsedNumber result) {
return false;
}

int initialOffset = segment.getOffset();
int currGroup = 0;
int separator = -1;
int lastSeparatorOffset = segment.getOffset();
int scientificAdjustment = 0;
int exponent = 0;
boolean hasPartialPrefix = false;
boolean seenBothSeparators = false;
while (segment.length() > 0) {
Expand Down Expand Up @@ -118,7 +121,7 @@ public boolean match(StringSegment segment, ParsedNumber result) {
// If found, save it in the DecimalQuantity or scientific adjustment.
if (digit >= 0) {
if (isScientific) {
scientificAdjustment = digit + scientificAdjustment * 10;
exponent = digit + exponent * 10;
} else {
if (result.quantity == null) {
result.quantity = new DecimalQuantity_DualStorageBCD();
Expand Down Expand Up @@ -163,15 +166,30 @@ public boolean match(StringSegment segment, ParsedNumber result) {
}

if (isScientific) {
result.quantity.adjustMagnitude(scientificAdjustment);
result.quantity.adjustMagnitude(exponent);
} else if (seenBothSeparators || (separator != -1 && decimalUniSet.contains(separator))) {
// The final separator was a decimal separator.
result.quantity.adjustMagnitude(-currGroup);
if (integerOnly) {
result.quantity.truncate();
segment.setOffset(lastSeparatorOffset);
}
} else if (separator != -1 && !groupingEnabled) {
// The final separator was a grouping separator, but we aren't accepting grouping.
// Reset the offset to immediately before that grouping separator.
result.quantity.adjustMagnitude(-currGroup);
} else if (separator != -1
&& ((requireGroupingMatch && groupingUniSet.contains(separator) && currGroup != grouping1)
|| !groupingEnabled)) {
result.quantity.truncate();
segment.setOffset(lastSeparatorOffset);
} else if (separator != -1 && requireGroupingMatch && groupingUniSet.contains(separator)
&& currGroup != grouping1) {
// The final separator was a grouping separator, and we have a mismatched grouping size.
// Reset the offset to the beginning of the number.
// TODO
result.quantity.adjustMagnitude(-currGroup);
result.quantity.roundToMagnitude(0, RoundingUtils.mathContextUnlimited(RoundingMode.FLOOR));
result.quantity.truncate();
segment.setOffset(lastSeparatorOffset);
// result.quantity = null;
// segment.setOffset(initialOffset);
}

return segment.length() == 0 || hasPartialPrefix || segment.isLeadingSurrogate();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
public class MinusSignMatcher extends SymbolMatcher {

public MinusSignMatcher() {
// FIXME
super("-", new UnicodeSet("[-_]"));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static NumberParserImpl createParserFromPattern(String pattern, boolean s
// Temporary frontend for testing.

NumberParserImpl parser = new NumberParserImpl();
ULocale locale = ULocale.ENGLISH;
ULocale locale = new ULocale("en_IN");
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);

MutablePatternModifier mod = new MutablePatternModifier(false);
Expand All @@ -47,15 +47,18 @@ public static NumberParserImpl createParserFromPattern(String pattern, boolean s
if (provider.containsSymbolType(AffixUtils.TYPE_PERMILLE)) {
flags |= ParsedNumber.FLAG_PERMILLE;
}
AffixMatcher.generateFromPatternModifier(mod, flags, parser);
AffixMatcher.generateFromPatternModifier(mod, flags, true, parser);

parser.addMatcher(WhitespaceMatcher.getInstance());
DecimalMatcher decimalMatcher = DecimalMatcher.getInstance(symbols);
decimalMatcher.requireGroupingMatch = strictGrouping;
decimalMatcher.grouping1 = 3;
decimalMatcher.grouping2 = 2;
parser.addMatcher(decimalMatcher);
parser.addMatcher(WhitespaceMatcher.getInstance());
parser.addMatcher(new MinusSignMatcher());
parser.addMatcher(new ScientificMatcher(symbols));
parser.addMatcher(new CurrencyMatcher(locale));
parser.addMatcher(new RequirementsMatcher());

parser.freeze();
return parser;
Expand All @@ -64,20 +67,27 @@ public static NumberParserImpl createParserFromPattern(String pattern, boolean s
public static Number parseStatic(String input,
ParsePosition ppos,
DecimalFormatProperties properties,
DecimalFormatSymbols symbols) {
NumberParserImpl parser = createParserFromProperties(properties, symbols);
DecimalFormatSymbols symbols,
boolean parseCurrency) {
NumberParserImpl parser = createParserFromProperties(properties, symbols, parseCurrency);
ParsedNumber result = new ParsedNumber();
parser.parse(input, true, result);
ppos.setIndex(result.charsConsumed);
return result.getDouble();
if (result.charsConsumed > 0) {
return result.getDouble();
} else {
return null;
}
}

public static NumberParserImpl createParserFromProperties(
DecimalFormatProperties properties,
DecimalFormatSymbols symbols) {
DecimalFormatSymbols symbols,
boolean parseCurrency) {
NumberParserImpl parser = new NumberParserImpl();
ULocale locale = symbols.getULocale();
Currency currency = CustomSymbolCurrency.resolve(properties.getCurrency(), locale, symbols);
boolean isStrict = properties.getParseMode() == ParseMode.STRICT;

//////////////////////
/// AFFIX MATCHERS ///
Expand All @@ -100,25 +110,40 @@ public static NumberParserImpl createParserFromProperties(
flags |= ParsedNumber.FLAG_PERMILLE;
}

AffixMatcher.generateFromPatternModifier(mod, flags, parser);
AffixMatcher.generateFromPatternModifier(mod, flags, !isStrict, parser);

///////////////////////////////
/// OTHER STANDARD MATCHERS ///
///////////////////////////////

if (!isStrict) {
parser.addMatcher(WhitespaceMatcher.getInstance());
parser.addMatcher(new PlusSignMatcher());
}
parser.addMatcher(new MinusSignMatcher());
DecimalMatcher decimalMatcher = DecimalMatcher.getInstance(symbols);
decimalMatcher.groupingEnabled = properties.getGroupingSize() > 0;
decimalMatcher.requireGroupingMatch = properties.getParseMode() == ParseMode.STRICT;
decimalMatcher.requireGroupingMatch = isStrict;
decimalMatcher.grouping1 = properties.getGroupingSize();
decimalMatcher.grouping2 = properties.getSecondaryGroupingSize();
decimalMatcher.integerOnly = properties.getParseIntegerOnly();
parser.addMatcher(decimalMatcher);
parser.addMatcher(WhitespaceMatcher.getInstance());
parser.addMatcher(new MinusSignMatcher());
parser.addMatcher(new ScientificMatcher(symbols));
parser.addMatcher(new RequirementsMatcher());
if (isStrict) {
parser.addMatcher(new RequireAffixMatcher());
}
if (isStrict && properties.getMinimumExponentDigits() > 0) {
parser.addMatcher(new RequireExponentMatcher());
}

////////////////////////
/// CURRENCY MATCHER ///
////////////////////////

parser.addMatcher(new CurrencyMatcher(locale));
if (parseCurrency) {
parser.addMatcher(new CurrencyMatcher(locale));
}

parser.freeze();
return parser;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,39 @@
*/
public class ParsedNumber {

public DecimalQuantity_DualStorageBCD quantity = null;
public DecimalQuantity_DualStorageBCD quantity;

/**
* The number of chars accepted during parsing. This is NOT necessarily the same as the StringSegment offset; "weak"
* chars, like whitespace, change the offset, but the charsConsumed is not touched until a "strong" char is
* encountered.
*/
public int charsConsumed = 0;
public int charsConsumed;

/**
* Boolean flags (see constants below).
*/
public int flags = 0;
public int flags;

/**
* The prefix string that got consumed.
*/
public String prefix = null;
public String prefix;

/**
* The suffix string that got consumed.
*/
public String suffix = null;
public String suffix;

/**
* The currency that got consumed.
*/
public String currencyCode = null;
public String currencyCode;

public static final int FLAG_NEGATIVE = 0x0001;
public static final int FLAG_PERCENT = 0x0002;
public static final int FLAG_PERMILLE = 0x0004;
public static final int FLAG_HAS_EXPONENT = 0x0008;

/** A Comparator that favors ParsedNumbers with the most chars consumed. */
public static final Comparator<ParsedNumber> COMPARATOR = new Comparator<ParsedNumber>() {
Expand All @@ -53,11 +54,24 @@ public int compare(ParsedNumber o1, ParsedNumber o2) {
}
};

public ParsedNumber() {
clear();
}

/**
* @param other
* Clears the data from this ParsedNumber, in effect failing the current parse.
*/
public void clear() {
quantity = null;
charsConsumed = 0;
flags = 0;
prefix = null;
suffix = null;
currencyCode = null;
}

public void copyFrom(ParsedNumber other) {
quantity = other.quantity;
quantity = other.quantity == null ? null : (DecimalQuantity_DualStorageBCD) other.quantity.createCopy();
charsConsumed = other.charsConsumed;
flags = other.flags;
prefix = other.prefix;
Expand Down

0 comments on commit 68340c8

Please sign in to comment.