mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
Implement decimal pattern parser
This commit is contained in:
parent
1fd4b8ff7a
commit
408347e460
|
@ -25,7 +25,16 @@ import org.teavm.classlib.java.util.TLocale;
|
|||
* @author Alexey Andreev
|
||||
*/
|
||||
public class TDecimalFormat extends TNumberFormat {
|
||||
private TDecimalFormatSymbols symbols;
|
||||
TDecimalFormatSymbols symbols;
|
||||
private String positivePrefix;
|
||||
private String negativePrefix;
|
||||
private String positiveSuffix;
|
||||
private String negativeSuffix;
|
||||
private int multiplier;
|
||||
private int groupingSize;
|
||||
private boolean decimalSeparatorAlwaysShown;
|
||||
private boolean parseBigDecimal;
|
||||
int exponentDigits;
|
||||
|
||||
public TDecimalFormat() {
|
||||
this(CLDRHelper.resolveDecimalFormat(TLocale.getDefault().getLanguage(), TLocale.getDefault().getCountry()));
|
||||
|
@ -47,8 +56,10 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
super.setMinimumIntegerDigits(decimalData.getMinimumIntegerDigits());
|
||||
}
|
||||
|
||||
public void applyPattern(@SuppressWarnings("unused") String pattern) {
|
||||
|
||||
public void applyPattern(String pattern) {
|
||||
TDecimalFormatParser parser = new TDecimalFormatParser();
|
||||
parser.parse(pattern);
|
||||
parser.apply(this);
|
||||
}
|
||||
|
||||
public DecimalFormatSymbols getDecimalFormatSymbols() {
|
||||
|
@ -69,4 +80,111 @@ public class TDecimalFormat extends TNumberFormat {
|
|||
public StringBuffer format(double value, StringBuffer buffer, TFieldPosition field) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getPositivePrefix() {
|
||||
return positivePrefix;
|
||||
}
|
||||
|
||||
public void setPositivePrefix(String newValue) {
|
||||
positivePrefix = newValue;
|
||||
}
|
||||
|
||||
public String getNegativePrefix() {
|
||||
return negativePrefix;
|
||||
}
|
||||
|
||||
public void setNegativePrefix(String newValue) {
|
||||
negativePrefix = newValue;
|
||||
}
|
||||
|
||||
public String getPositiveSuffix() {
|
||||
return positiveSuffix;
|
||||
}
|
||||
|
||||
public void setPositiveSuffix(String newValue) {
|
||||
positiveSuffix = newValue;
|
||||
}
|
||||
|
||||
public String getNegativeSuffix() {
|
||||
return negativeSuffix;
|
||||
}
|
||||
|
||||
public void setNegativeSuffix(String newValue) {
|
||||
negativeSuffix = newValue;
|
||||
}
|
||||
|
||||
public int getMultiplier() {
|
||||
return multiplier;
|
||||
}
|
||||
|
||||
public void setMultiplier(int newValue) {
|
||||
multiplier = newValue;
|
||||
}
|
||||
|
||||
public int getGroupingSize() {
|
||||
return groupingSize;
|
||||
}
|
||||
|
||||
public void setGroupingSize(int newValue) {
|
||||
groupingSize = newValue;
|
||||
}
|
||||
|
||||
public boolean isDecimalSeparatorAlwaysShown() {
|
||||
return decimalSeparatorAlwaysShown;
|
||||
}
|
||||
|
||||
public void setDecimalSeparatorAlwaysShown(boolean newValue) {
|
||||
decimalSeparatorAlwaysShown = newValue;
|
||||
}
|
||||
|
||||
public boolean isParseBigDecimal() {
|
||||
return parseBigDecimal;
|
||||
}
|
||||
|
||||
public void setParseBigDecimal(boolean newValue) {
|
||||
parseBigDecimal = newValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof TDecimalFormat)) {
|
||||
return false;
|
||||
}
|
||||
TDecimalFormat other = (TDecimalFormat)obj;
|
||||
if (!super.equals(obj)) {
|
||||
return false;
|
||||
}
|
||||
return positivePrefix.equals(other.positivePrefix) &&
|
||||
positiveSuffix.equals(other.positiveSuffix) &&
|
||||
negativePrefix.equals(other.negativePrefix) &&
|
||||
negativeSuffix.equals(other.negativeSuffix) &&
|
||||
multiplier == other.multiplier &&
|
||||
groupingSize == other.groupingSize &&
|
||||
decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown &&
|
||||
parseBigDecimal == other.parseBigDecimal &&
|
||||
exponentDigits == other.exponentDigits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = result * 31 + positivePrefix.hashCode();
|
||||
result = result * 31 + positiveSuffix.hashCode();
|
||||
result = result * 31 + negativePrefix.hashCode();
|
||||
result = result * 31 + negativeSuffix.hashCode();
|
||||
result = result * 31 + multiplier;
|
||||
result = result * 31 + groupingSize;
|
||||
result = result * 31 + (decimalSeparatorAlwaysShown ? 1 : 0);
|
||||
result = result * 31 + (parseBigDecimal ? 1 : 0);
|
||||
result = result * 31 + exponentDigits;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
* Copyright 2015 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.classlib.java.text;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class TDecimalFormatParser {
|
||||
private String positivePrefix;
|
||||
private String positiveSuffix;
|
||||
private String negativePrefix;
|
||||
private String negativeSuffix;
|
||||
private int groupSize;
|
||||
private int minimumIntLength;
|
||||
private int intLength;
|
||||
private int minimumFracLength;
|
||||
private int fracLength;
|
||||
private int exponentLength;
|
||||
private boolean decimalSeparatorRequired;
|
||||
private String string;
|
||||
private int index;
|
||||
|
||||
public void parse(String string) {
|
||||
groupSize = 0;
|
||||
minimumFracLength = 0;
|
||||
fracLength = 0;
|
||||
exponentLength = 0;
|
||||
decimalSeparatorRequired = false;
|
||||
this.string = string;
|
||||
index = 0;
|
||||
positivePrefix = parseText(false, false);
|
||||
if (index == string.length()) {
|
||||
throw new IllegalArgumentException("Positive number pattern not found in " + string);
|
||||
}
|
||||
parseNumber(true);
|
||||
if (index < string.length() && string.charAt(index) != ';') {
|
||||
positiveSuffix = parseText(true, false);
|
||||
}
|
||||
if (index < string.length()) {
|
||||
if (string.charAt(index++) != ';') {
|
||||
throw new IllegalArgumentException("Expected ';' at " + index + " in " + string);
|
||||
}
|
||||
negativePrefix = parseText(false, true);
|
||||
parseNumber(false);
|
||||
negativeSuffix = parseText(true, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void apply(TDecimalFormat format) {
|
||||
format.setPositivePrefix(positivePrefix);
|
||||
format.setPositiveSuffix(positiveSuffix);
|
||||
format.setNegativePrefix(negativePrefix != null ? negativePrefix :
|
||||
format.symbols.getMinusSign() + positivePrefix);
|
||||
format.setNegativeSuffix(negativeSuffix != null ? negativeSuffix : positiveSuffix);
|
||||
format.setGroupingSize(groupSize);
|
||||
format.setGroupingUsed(groupSize > 0);
|
||||
format.setMinimumIntegerDigits(minimumIntLength);
|
||||
format.setMaximumIntegerDigits(intLength);
|
||||
format.setMinimumFractionDigits(minimumFracLength);
|
||||
format.setMaximumFractionDigits(fracLength);
|
||||
format.setDecimalSeparatorAlwaysShown(decimalSeparatorRequired);
|
||||
format.exponentDigits = exponentLength;
|
||||
}
|
||||
|
||||
private String parseText(boolean suffix, boolean end) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
loop: while (index < string.length()) {
|
||||
char c = string.charAt(index);
|
||||
switch (c) {
|
||||
case '#':
|
||||
case '0':
|
||||
if (suffix) {
|
||||
throw new IllegalArgumentException("Prefix contains special character at " + index + " in " +
|
||||
string);
|
||||
}
|
||||
break loop;
|
||||
case ';':
|
||||
if (end) {
|
||||
throw new IllegalArgumentException("Prefix contains special character at " + index + " in " +
|
||||
string);
|
||||
}
|
||||
break loop;
|
||||
case '.':
|
||||
case 'E':
|
||||
throw new IllegalArgumentException("Prefix contains special character at " + index + " in " +
|
||||
string);
|
||||
case '\'': {
|
||||
++index;
|
||||
int next = string.indexOf('\'', index);
|
||||
if (next < 0) {
|
||||
throw new IllegalArgumentException("Quote opened at " + index + " was not closed in " +
|
||||
string);
|
||||
}
|
||||
if (next == index) {
|
||||
sb.append('\'');
|
||||
} else {
|
||||
sb.append(string.substring(index, next));
|
||||
}
|
||||
index = next + 1;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
sb.append(c);
|
||||
++index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void parseNumber(boolean apply) {
|
||||
parseIntegerPart(apply);
|
||||
if (index < string.length() && string.charAt(index) == '.') {
|
||||
++index;
|
||||
parseFractionalPart(apply);
|
||||
}
|
||||
if (index < string.length() && string.charAt(index) == 'E') {
|
||||
++index;
|
||||
parseExponent(apply);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseIntegerPart(boolean apply) {
|
||||
int lastGroup = index;
|
||||
boolean optionalDigits = true;
|
||||
int length = 0;
|
||||
int minimumLength = 0;
|
||||
loop: while (index < string.length()) {
|
||||
switch (string.charAt(index)) {
|
||||
case '#':
|
||||
if (!optionalDigits) {
|
||||
throw new IllegalArgumentException("Unexpected '#' at non-optional digit part at " + index +
|
||||
" in " + string);
|
||||
}
|
||||
++length;
|
||||
break;
|
||||
case ',':
|
||||
if (lastGroup + 1 == index) {
|
||||
throw new IllegalArgumentException("Two commas at " + index + " in " + string);
|
||||
}
|
||||
if (apply) {
|
||||
groupSize = index - lastGroup;
|
||||
}
|
||||
break;
|
||||
case '0':
|
||||
optionalDigits = false;
|
||||
++length;
|
||||
++minimumLength;
|
||||
break;
|
||||
default:
|
||||
break loop;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
if (length == 0) {
|
||||
throw new IllegalArgumentException("Pattern does not specify integer digits at " + index +
|
||||
" in " + string);
|
||||
}
|
||||
if (apply) {
|
||||
intLength = length;
|
||||
minimumIntLength = minimumLength;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseFractionalPart(boolean apply) {
|
||||
boolean optionalDigits = false;
|
||||
int length = 0;
|
||||
int minimumLength = 0;
|
||||
loop: while (index < string.length()) {
|
||||
switch (string.charAt(index)) {
|
||||
case '#':
|
||||
++length;
|
||||
optionalDigits = true;
|
||||
break;
|
||||
case ',':
|
||||
throw new IllegalArgumentException("Group separator found at fractional part at " + index +
|
||||
" in " + string);
|
||||
case '0':
|
||||
if (!optionalDigits) {
|
||||
throw new IllegalArgumentException("Unexpected '0' at optional digit part at " + index +
|
||||
" in " + string);
|
||||
}
|
||||
++length;
|
||||
++minimumLength;
|
||||
break;
|
||||
case '.':
|
||||
throw new IllegalArgumentException("Unexpected second decimal separator at " + index +
|
||||
" in " + string);
|
||||
default:
|
||||
break loop;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
if (apply) {
|
||||
fracLength = length;
|
||||
minimumFracLength = minimumLength;
|
||||
decimalSeparatorRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void parseExponent(boolean apply) {
|
||||
int length = 0;
|
||||
loop: while (index < string.length()) {
|
||||
switch (string.charAt(index)) {
|
||||
case '#':
|
||||
case ',':
|
||||
case '.':
|
||||
case 'E':
|
||||
throw new IllegalArgumentException("Unexpected char at exponent at " + index +
|
||||
" in " + string);
|
||||
case '0':
|
||||
++length;
|
||||
break;
|
||||
default:
|
||||
break loop;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
if (length == 0) {
|
||||
throw new IllegalArgumentException("Pattern does not specify exponent digits at " + index +
|
||||
" in " + string);
|
||||
}
|
||||
if (apply) {
|
||||
exponentLength = length;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ package org.teavm.classlib.java.util;
|
|||
* @author shannah
|
||||
*/
|
||||
public class TObservable {
|
||||
TList<TObserver> observers = new TArrayList<TObserver>();
|
||||
TList<TObserver> observers = new TArrayList<>();
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class TObservable {
|
|||
/**
|
||||
* Adds the specified observer to the list of observers. If it is already
|
||||
* registered, it is not added a second time.
|
||||
*
|
||||
*
|
||||
* @param observer
|
||||
* the Observer to add.
|
||||
*/
|
||||
|
@ -58,7 +58,7 @@ public class TObservable {
|
|||
|
||||
/**
|
||||
* Returns the number of observers registered to this {@code Observable}.
|
||||
*
|
||||
*
|
||||
* @return the number of observers.
|
||||
*/
|
||||
public int countObservers() {
|
||||
|
@ -68,7 +68,7 @@ public class TObservable {
|
|||
/**
|
||||
* Removes the specified observer from the list of observers. Passing null
|
||||
* won't do anything.
|
||||
*
|
||||
*
|
||||
* @param observer
|
||||
* the observer to remove.
|
||||
*/
|
||||
|
@ -85,7 +85,7 @@ public class TObservable {
|
|||
|
||||
/**
|
||||
* Returns the changed flag for this {@code Observable}.
|
||||
*
|
||||
*
|
||||
* @return {@code true} when the changed flag for this {@code Observable} is
|
||||
* set, {@code false} otherwise.
|
||||
*/
|
||||
|
@ -108,11 +108,10 @@ public class TObservable {
|
|||
* If {@code hasChanged()} returns {@code true}, calls the {@code update()}
|
||||
* method for every Observer in the list of observers using the specified
|
||||
* argument. Afterwards calls {@code clearChanged()}.
|
||||
*
|
||||
*
|
||||
* @param data
|
||||
* the argument passed to {@code update()}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void notifyObservers(Object data) {
|
||||
int size = 0;
|
||||
TObserver[] arrays = null;
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package org.teavm.classlib.java.text;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Locale;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class DecimalFormatTest {
|
||||
@Test
|
||||
public void parsesIntegerPattern() {
|
||||
DecimalFormat format = new DecimalFormat("00");
|
||||
assertEquals(2, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isDecimalSeparatorAlwaysShown());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(0, format.getMinimumFractionDigits());
|
||||
assertEquals(0, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("##");
|
||||
assertEquals(0, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isDecimalSeparatorAlwaysShown());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(0, format.getMinimumFractionDigits());
|
||||
assertEquals(0, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("#,##0");
|
||||
assertEquals(1, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isDecimalSeparatorAlwaysShown());
|
||||
assertTrue(format.isGroupingUsed());
|
||||
assertEquals(3, format.getGroupingSize());
|
||||
assertEquals(0, format.getMinimumFractionDigits());
|
||||
assertEquals(0, format.getMaximumFractionDigits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void selectsLastGrouping() {
|
||||
DecimalFormat format = new DecimalFormat("#,0,000");
|
||||
assertEquals(4, format.getMinimumIntegerDigits());
|
||||
assertTrue(format.isGroupingUsed());
|
||||
assertEquals(3, format.getGroupingSize());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsesPrefixAndSuffixInPattern() {
|
||||
DecimalFormat format = new DecimalFormat("(00)", new DecimalFormatSymbols(Locale.ENGLISH));
|
||||
assertEquals(2, format.getMinimumIntegerDigits());
|
||||
assertEquals("(", format.getPositivePrefix());
|
||||
assertEquals(")", format.getPositiveSuffix());
|
||||
assertEquals("-(", format.getNegativePrefix());
|
||||
assertEquals(")", format.getNegativeSuffix());
|
||||
|
||||
format = new DecimalFormat("+(00);-{#}", new DecimalFormatSymbols(Locale.ENGLISH));
|
||||
assertEquals(2, format.getMinimumIntegerDigits());
|
||||
assertEquals("+(", format.getPositivePrefix());
|
||||
assertEquals(")", format.getPositiveSuffix());
|
||||
assertEquals("-{", format.getNegativePrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsesFractionalPattern() {
|
||||
DecimalFormat format = new DecimalFormat("#.");
|
||||
assertEquals(1, format.getMinimumIntegerDigits());
|
||||
assertTrue(format.isDecimalSeparatorAlwaysShown());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(0, format.getMinimumFractionDigits());
|
||||
assertEquals(0, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("#.00");
|
||||
assertEquals(0, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(2, format.getMinimumFractionDigits());
|
||||
assertEquals(2, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("#.00##");
|
||||
assertEquals(0, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(2, format.getMinimumFractionDigits());
|
||||
assertEquals(4, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("#00.00##");
|
||||
assertEquals(2, format.getMinimumIntegerDigits());
|
||||
assertFalse(format.isGroupingUsed());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(2, format.getMinimumFractionDigits());
|
||||
assertEquals(4, format.getMaximumFractionDigits());
|
||||
|
||||
format = new DecimalFormat("#,#00.00##");
|
||||
assertEquals(2, format.getMinimumIntegerDigits());
|
||||
assertTrue(format.isGroupingUsed());
|
||||
assertEquals(3, format.getGroupingSize());
|
||||
assertEquals(2, format.getMinimumFractionDigits());
|
||||
assertEquals(4, format.getMaximumFractionDigits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsesExponentialPattern() {
|
||||
DecimalFormat format = new DecimalFormat("##0E00");
|
||||
assertEquals(1, format.getMinimumIntegerDigits());
|
||||
assertEquals(0, format.getGroupingSize());
|
||||
assertEquals(0, format.getMinimumFractionDigits());
|
||||
assertEquals(0, format.getMaximumFractionDigits());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user