|
|
@@ -9,23 +9,18 @@ package net.ranides.assira.text;
|
|
|
import java.io.IOException;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.BigInteger;
|
|
|
-import java.text.ChoiceFormat;
|
|
|
-import java.text.DateFormat;
|
|
|
-import java.text.DecimalFormat;
|
|
|
-import java.text.DecimalFormatSymbols;
|
|
|
-import java.text.NumberFormat;
|
|
|
-import java.text.ParsePosition;
|
|
|
-import java.text.SimpleDateFormat;
|
|
|
+import java.text.*;
|
|
|
import java.time.Instant;
|
|
|
+import java.time.LocalDateTime;
|
|
|
import java.time.ZoneOffset;
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
import java.util.Date;
|
|
|
-import java.util.IllegalFormatConversionException;
|
|
|
import java.util.Locale;
|
|
|
import java.util.Map;
|
|
|
-import java.util.Objects;
|
|
|
import java.util.function.BiFunction;
|
|
|
import java.util.function.Function;
|
|
|
+import java.util.regex.Matcher;
|
|
|
+import java.util.regex.Pattern;
|
|
|
import net.ranides.assira.collection.maps.Cache;
|
|
|
import net.ranides.assira.collection.maps.HashMap;
|
|
|
import net.ranides.assira.generic.CompareUtils;
|
|
|
@@ -48,9 +43,9 @@ public final class ResolveDialect {
|
|
|
|
|
|
private static final class Li { // NOPMD - lazy init idiom
|
|
|
|
|
|
- private static final Cache<String, ResolveDialect> DIALECTS = new Cache<>(32,4);
|
|
|
+ public static final Cache<String, ResolveDialect> DIALECTS = new Cache<>(32,4);
|
|
|
|
|
|
- private static final ResolveDialect DEFAULT = new ResolveDialect(Locale.getDefault().getCountry());
|
|
|
+ public static final ResolveDialect DEFAULT = new ResolveDialect(Locale.getDefault().getCountry());
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -68,7 +63,7 @@ public final class ResolveDialect {
|
|
|
Locale locale = new Locale(name);
|
|
|
DecimalFormatSymbols us = DecimalFormatSymbols.getInstance(Locale.US);
|
|
|
|
|
|
- put("", "", r -> new FGeneric(r));
|
|
|
+ putFormat("", "", r -> new FGeneric(r));
|
|
|
|
|
|
// number : 2 + 3 5
|
|
|
// date : 2 + 8 10
|
|
|
@@ -77,58 +72,60 @@ public final class ResolveDialect {
|
|
|
// metric : 1 + 4 5
|
|
|
// binary : 1 + 6 7
|
|
|
// : 40 x language
|
|
|
-
|
|
|
- put("number", (r,p) -> new FNumber(r, new DecimalFormat(p,us)));
|
|
|
- put("number", "", r -> new FNumber(r, DecimalFormat.getInstance(locale)));
|
|
|
- put("number", "integer", r -> new FNumber(r, DecimalFormat.getIntegerInstance(locale)));
|
|
|
- put("number", "currency", r -> new FNumber(r, getCurrencyFormat(locale)));
|
|
|
- put("number", "percent", r -> new FNumber(r, DecimalFormat.getPercentInstance(locale)));
|
|
|
-
|
|
|
- put("date", (r,p) -> new FDateTime(r, new SimpleDateFormat(p,locale)));
|
|
|
- put("date", "", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.DEFAULT,locale)));
|
|
|
- put("date", "short", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.SHORT,locale)));
|
|
|
- put("date", "medium", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.MEDIUM,locale)));
|
|
|
- put("date", "long", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.LONG,locale)));
|
|
|
- put("date", "full", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.FULL,locale)));
|
|
|
- put("date", "iso", r -> new FDateTime8(r, "yyyy-MM-dd'T'HH:mmX"));
|
|
|
- put("date", "gnu", r -> new FDateTime(r, new SimpleDateFormat("yyyyMMddHHmm",Locale.ROOT)));
|
|
|
- put("date", "trace", r -> new FDateTime(r, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS",Locale.ROOT)));
|
|
|
- put("date", "local", r -> new FDateTime(r, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.ROOT)));
|
|
|
-
|
|
|
- put("time", (r,p) -> new FDateTime(r, new SimpleDateFormat(p,locale)));
|
|
|
- put("time", "", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.DEFAULT,locale)));
|
|
|
- put("time", "short", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.SHORT,locale)));
|
|
|
- put("time", "medium", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.MEDIUM,locale)));
|
|
|
- put("time", "long", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.LONG,locale)));
|
|
|
- put("time", "full", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.FULL,locale)));
|
|
|
- put("time", "iso", r -> new FDateTime8(r, "HH:mm:ssX"));
|
|
|
- put("time", "gnu", r -> new FDateTime(r, new SimpleDateFormat("HHmmss",Locale.ROOT)));
|
|
|
- put("time", "trace", r -> new FDateTime(r, new SimpleDateFormat("HH:mm:ss.SSS",Locale.ROOT)));
|
|
|
- put("time", "local", r -> new FDateTime(r, new SimpleDateFormat("HH:mm:ss",Locale.ROOT)));
|
|
|
-
|
|
|
- put("hex", "", r -> new FHexArray(r));
|
|
|
- put("hex", "array", r -> new FHexArray(r));
|
|
|
- put("hex", "stream", r -> new FHexStream(r));
|
|
|
-
|
|
|
- put("metric", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.MP));
|
|
|
- put("metric/si", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.MP));
|
|
|
- put("metric/e", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.ME));
|
|
|
- put("metric", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.MP));
|
|
|
- put("metric/si", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.MP));
|
|
|
- put("metric/e", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.ME));
|
|
|
-
|
|
|
- put("binary", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BP));
|
|
|
- put("binary/iec", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BP));
|
|
|
- put("binary/e", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BE));
|
|
|
- put("binary/knuth", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BK));
|
|
|
- put("binary", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BP));
|
|
|
- put("binary/iec", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BP));
|
|
|
- put("binary/e", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BE));
|
|
|
- put("binary/knuth", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BK));
|
|
|
-
|
|
|
- put("choice", (r,p) -> new FChoice(r, new ChoiceFormat(p)));
|
|
|
- }
|
|
|
|
|
|
+ putFormat("number", (r,p) -> new FNumber(r, new DecimalFormat(p,us)));
|
|
|
+ putFormat("number", "", r -> new FNumber(r, DecimalFormat.getInstance(locale)));
|
|
|
+ putFormat("number", "integer", r -> new FNumber(r, DecimalFormat.getIntegerInstance(locale)));
|
|
|
+ putFormat("number", "c++", r -> new FNumber(r, getDecimalFormat(Locale.US, '.','\'')));
|
|
|
+ putFormat("number", "java", r -> new FNumber(r, getDecimalFormat(Locale.US, '.','_')));
|
|
|
+ putFormat("number", "currency", r -> new FNumber(r, getCurrencyFormat(locale)));
|
|
|
+ putFormat("number", "percent", r -> new FNumber(r, DecimalFormat.getPercentInstance(locale)));
|
|
|
+
|
|
|
+ putFormat("date", (r,p) -> new FDateTime(r, new SimpleDateFormat(p,locale)));
|
|
|
+ putFormat("date", "", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.DEFAULT,locale)));
|
|
|
+ putFormat("date", "short", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.SHORT,locale)));
|
|
|
+ putFormat("date", "medium", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.MEDIUM,locale)));
|
|
|
+ putFormat("date", "long", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.LONG,locale)));
|
|
|
+ putFormat("date", "full", r -> new FDateTime(r, DateFormat.getDateInstance(DateFormat.FULL,locale)));
|
|
|
+ putFormat("date", "iso", r -> new FDateTime8(r, "yyyy-MM-dd'T'HH:mmX"));
|
|
|
+ putFormat("date", "gnu", r -> new FDateTime(r, new SimpleDateFormat("yyyyMMddHHmm",Locale.ROOT)));
|
|
|
+ putFormat("date", "trace", r -> new FDateTime(r, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS",Locale.ROOT)));
|
|
|
+ putFormat("date", "local", r -> new FDateTime(r, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",Locale.ROOT)));
|
|
|
+
|
|
|
+ putFormat("time", (r,p) -> new FDateTime(r, new SimpleDateFormat(p,locale)));
|
|
|
+ putFormat("time", "", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.DEFAULT,locale)));
|
|
|
+ putFormat("time", "short", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.SHORT,locale)));
|
|
|
+ putFormat("time", "medium", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.MEDIUM,locale)));
|
|
|
+ putFormat("time", "long", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.LONG,locale)));
|
|
|
+ putFormat("time", "full", r -> new FDateTime(r, DateFormat.getTimeInstance(DateFormat.FULL,locale)));
|
|
|
+ putFormat("time", "iso", r -> new FDateTime8(r, "HH:mm:ssX"));
|
|
|
+ putFormat("time", "gnu", r -> new FDateTime(r, new SimpleDateFormat("HHmmss",Locale.ROOT)));
|
|
|
+ putFormat("time", "trace", r -> new FDateTime(r, new SimpleDateFormat("HH:mm:ss.SSS",Locale.ROOT)));
|
|
|
+ putFormat("time", "local", r -> new FDateTime(r, new SimpleDateFormat("HH:mm:ss",Locale.ROOT)));
|
|
|
+
|
|
|
+ putFormat("hex", "", r -> new FHexArray(r));
|
|
|
+ putFormat("hex", "array", r -> new FHexArray(r));
|
|
|
+ putFormat("hex", "stream", r -> new FHexStream(r));
|
|
|
+
|
|
|
+ putFormat("metric", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.MP));
|
|
|
+ putFormat("metric/si", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.MP));
|
|
|
+ putFormat("metric/e", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.ME));
|
|
|
+ putFormat("metric", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.MP));
|
|
|
+ putFormat("metric/si", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.MP));
|
|
|
+ putFormat("metric/e", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.ME));
|
|
|
+
|
|
|
+ putFormat("binary", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BP));
|
|
|
+ putFormat("binary/iec", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BP));
|
|
|
+ putFormat("binary/e", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BE));
|
|
|
+ putFormat("binary/knuth", (r,p) -> new FEngineer(r, new DecimalFormat(p,us), FormatNumber.BK));
|
|
|
+ putFormat("binary", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BP));
|
|
|
+ putFormat("binary/iec", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BP));
|
|
|
+ putFormat("binary/e", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BE));
|
|
|
+ putFormat("binary/knuth", "", r -> new FEngineer(r, DecimalFormat.getInstance(Locale.US), FormatNumber.BK));
|
|
|
+
|
|
|
+ putFormat("choice", (r,p) -> new FChoice(r, new ChoiceFormat(p)));
|
|
|
+ }
|
|
|
+
|
|
|
public static ResolveDialect getDefault() {
|
|
|
return Li.DEFAULT;
|
|
|
}
|
|
|
@@ -166,12 +163,11 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
- void put(String format, String pattern, Function<Resolver,ResolveFormat.Token> token) {
|
|
|
+ private void putFormat(String format, String pattern, Function<Resolver,ResolveFormat.Token> token) {
|
|
|
mDefined.put(new TokenKey(format, pattern), token);
|
|
|
}
|
|
|
|
|
|
- void put(String format, BiFunction<Resolver,String,ResolveFormat.Token> token) {
|
|
|
+ private void putFormat(String format, BiFunction<Resolver,String,ResolveFormat.Token> token) {
|
|
|
mPattern.put(format, token);
|
|
|
}
|
|
|
|
|
|
@@ -198,6 +194,16 @@ public final class ResolveDialect {
|
|
|
return nf;
|
|
|
}
|
|
|
|
|
|
+ private DecimalFormat getDecimalFormat(Locale locale, char dseparator, char gseparator) {
|
|
|
+ DecimalFormat fmt = (DecimalFormat)DecimalFormat.getInstance(locale);
|
|
|
+ DecimalFormatSymbols dfs = fmt.getDecimalFormatSymbols();
|
|
|
+ dfs.setDecimalSeparator(dseparator);
|
|
|
+ dfs.setGroupingSeparator(gseparator);
|
|
|
+ fmt.setGroupingUsed(true);
|
|
|
+ fmt.setDecimalFormatSymbols(dfs);
|
|
|
+ return fmt;
|
|
|
+ }
|
|
|
+
|
|
|
private static StrBuffer asHex(StrBuffer target, byte value) {
|
|
|
int ivalue = value & 0xFF;
|
|
|
target.append( HC_TABLE[ivalue >>> 4] );
|
|
|
@@ -252,11 +258,12 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public final void parse(String source, ParsePosition position, Object context) {
|
|
|
- set(context, parse(source, position));
|
|
|
+ public final void parse(String source, Object context) throws ParseException {
|
|
|
+// iresolver.type(context)
|
|
|
+ set(context, parse(source));
|
|
|
}
|
|
|
|
|
|
- public abstract Object parse(String source, ParsePosition position);
|
|
|
+ public abstract Object parse(String source) throws ParseException;
|
|
|
}
|
|
|
|
|
|
private static final class FNumber extends RToken {
|
|
|
@@ -268,14 +275,46 @@ public final class ResolveDialect {
|
|
|
this.format = nf;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ if(format instanceof DecimalFormat) {
|
|
|
+ DecimalFormatSymbols dfs = ((DecimalFormat)format).getDecimalFormatSymbols();
|
|
|
+ StrBuilder s = new StrBuilder();
|
|
|
+ s.append("(");
|
|
|
+ s.append(dfs.getMinusSign()).append("?");
|
|
|
+ digits(s, dfs);
|
|
|
+ s.append("+");
|
|
|
+ s.append("(?:")
|
|
|
+ .append(dfs.getExponentSeparator())
|
|
|
+ .append("|")
|
|
|
+ .append(dfs.getExponentSeparator().toLowerCase(Locale.ROOT))
|
|
|
+ .append(")?");
|
|
|
+ digits(s, dfs);
|
|
|
+ s.append("*");
|
|
|
+ s.append("%?");
|
|
|
+ s.append(")");
|
|
|
+ return s.toString();
|
|
|
+ } else {
|
|
|
+ return "((?:0x)?[0-9.,'A-Fa-f]+)";
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private StrBuilder digits(StrBuilder s, DecimalFormatSymbols dfs) {
|
|
|
+ s.append("[0-9");
|
|
|
+ s.append(dfs.getDecimalSeparator());
|
|
|
+ s.append(dfs.getGroupingSeparator());
|
|
|
+ s.append("]");
|
|
|
+ return s;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
target.append(format.format(get(context)));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- return format.parse(source, position);
|
|
|
+ public Object parse(String source) throws ParseException {
|
|
|
+ return format.parse(source);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -289,14 +328,19 @@ public final class ResolveDialect {
|
|
|
this.format = nf;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "(.+)";
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
target.append(format.format(get(context,Date.class)));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- return format.parse(source, position);
|
|
|
+ public Object parse(String source) throws ParseException {
|
|
|
+ return format.parse(source);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -309,6 +353,11 @@ public final class ResolveDialect {
|
|
|
super(resolver);
|
|
|
this.format = DateTimeFormatter.ofPattern(pattern).withZone(ZoneOffset.UTC);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "(.+)";
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
@@ -316,8 +365,8 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- return format.parse(source, position);
|
|
|
+ public Object parse(String source) {
|
|
|
+ return LocalDateTime.parse(source, format);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
@@ -332,6 +381,11 @@ public final class ResolveDialect {
|
|
|
super(resolver);
|
|
|
this.format = nf;
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "(.+)";
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
@@ -339,17 +393,24 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- return format.parse(source, position);
|
|
|
+ public Object parse(String source) throws ParseException {
|
|
|
+ return format.parse(source);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
private static final class FHexArray extends RToken {
|
|
|
|
|
|
+ private static final Pattern RE_PARSE = Pattern.compile("\\[([0-9]+)\\]\\{(.*)\\}");
|
|
|
+
|
|
|
public FHexArray(Resolver resolver) {
|
|
|
super(resolver);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "(\\[[0-9]+\\]\\{(?:0x[0-9a-fA-F]{2}?)?(?:,0x[0-9a-fA-F]{2})*\\})";
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
@@ -375,9 +436,20 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- throw new UnsupportedOperationException("Not supported yet.");
|
|
|
+ public Object parse(String source) throws ParseException {
|
|
|
+ Matcher hit = RE_PARSE.matcher(source);
|
|
|
+ if( !hit.matches() ) {
|
|
|
+ throw new ParseException("Value is not byte array: " + source, 0);
|
|
|
+ }
|
|
|
+ int size = Integer.parseInt(hit.group(1));
|
|
|
+ byte[] array = new byte[size];
|
|
|
+ int index = 0 ;
|
|
|
+ for(String v : hit.group(2).split(",")) {
|
|
|
+ array[index++] = Byte.parseByte(v.substring(2), 16);
|
|
|
+ }
|
|
|
+ return array;
|
|
|
}
|
|
|
+
|
|
|
|
|
|
}
|
|
|
|
|
|
@@ -386,6 +458,11 @@ public final class ResolveDialect {
|
|
|
public FHexStream(Resolver resolver) {
|
|
|
super(resolver);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "((?:[0-9A-Fa-f]{2})?(?: [0-9A-Fa-f]{2})*)";
|
|
|
+ }
|
|
|
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
@@ -404,26 +481,42 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- throw new UnsupportedOperationException("Not supported yet.");
|
|
|
+ public Object parse(String source) {
|
|
|
+ String[] ss = source.split(" ");
|
|
|
+ int n = ss.length;
|
|
|
+ byte[] array = new byte[n];
|
|
|
+ for(int i=0; i<n; i++) {
|
|
|
+ array[i] = Byte.parseByte(ss[i], 16);
|
|
|
+ }
|
|
|
+ return array;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- private static final class FEngineer extends RToken {
|
|
|
+ private static final class FEngineer implements ResolveFormat.Token {
|
|
|
|
|
|
+ private final Resolver iresolver;
|
|
|
private final NumberFormat nf;
|
|
|
private final UnitPrefix[] units;
|
|
|
+ private final String re;
|
|
|
+ private final Pattern regex;
|
|
|
|
|
|
public FEngineer(Resolver resolver, NumberFormat nf, UnitPrefix[] units) {
|
|
|
- super(resolver);
|
|
|
+ this.iresolver = resolver;
|
|
|
this.nf = nf;
|
|
|
this.units = units;
|
|
|
+ this.re = "([0-9]+(?:\\.[0-9]+)?(?:" + StringUtils.join(units, "|", b -> b.text()) + "))";
|
|
|
+ this.regex = Pattern.compile("([0-9]+(?:\\.[0-9]+)?)(" + StringUtils.join(units, "|", b -> b.text()) + ")");
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return re;
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
- Object object = get(context);
|
|
|
+ Object object = iresolver.get(context);
|
|
|
if (object instanceof BigInteger) {
|
|
|
BigInteger value = (BigInteger) object;
|
|
|
if(value.bitLength()<64) {
|
|
|
@@ -450,10 +543,40 @@ public final class ResolveDialect {
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public Object parse(String source, ParsePosition position) {
|
|
|
- throw new UnsupportedOperationException("Not supported yet.");
|
|
|
+ public void parse(String source, Object context) throws ParseException {
|
|
|
+ Matcher hit = regex.matcher(source);
|
|
|
+ if(!hit.matches()) {
|
|
|
+ throw new IllegalArgumentException("Cannot parse Number: " + source);
|
|
|
+ }
|
|
|
+ UnitPrefix unit = unit(hit.group(2));
|
|
|
+ IClass type = iresolver.type(context);
|
|
|
+
|
|
|
+ Object out;
|
|
|
+ if (type.isSubclass(IClass.typeinfo(BigInteger.class))) {
|
|
|
+ out = new BigDecimal(hit.group(1)).multiply(unit.decimalValue()).toBigInteger();
|
|
|
+ }
|
|
|
+ else if (type.isSubclass(IClass.typeinfo(BigDecimal.class))) {
|
|
|
+ out = new BigDecimal(hit.group(1)).multiply(unit.decimalValue());
|
|
|
+ }
|
|
|
+ else if(IAttribute.INTEGER.matches(type)) {
|
|
|
+ out = LexicalCast.cast(Long.parseLong(hit.group(1)) * unit.longValue(), type);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ out = LexicalCast.cast(Double.parseDouble(hit.group(1)) * unit.doubleValue(), type);
|
|
|
+ }
|
|
|
+ iresolver.set(context, out);
|
|
|
+ }
|
|
|
+
|
|
|
+ private UnitPrefix unit(String name) {
|
|
|
+ for(UnitPrefix u : units) {
|
|
|
+ if(u.text().equals(name)) {
|
|
|
+ return u;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ throw new IllegalArgumentException("Unknown prefix: " + name);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
private void vappend(Appendable target, long value) throws IOException {
|
|
|
if(value < 0) {
|
|
|
target.append('-');
|
|
|
@@ -509,17 +632,19 @@ public final class ResolveDialect {
|
|
|
this.resolver = resolver;
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public String regex() {
|
|
|
+ return "(.+)";
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public void append(Appendable target, Object context) throws IOException {
|
|
|
target.append(String.valueOf(resolver.get(context)));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
- public void parse(String source, ParsePosition position, Object context) {
|
|
|
- IClass type = resolver.type(context);
|
|
|
- Object value = null;
|
|
|
- resolver.set(context, value);
|
|
|
- throw new UnsupportedOperationException("Not supported yet.");
|
|
|
+ public void parse(String source, Object context) {
|
|
|
+ resolver.set(context, LexicalCast.cast(source, resolver.type(context)));
|
|
|
}
|
|
|
|
|
|
}
|