Browse Source

resolve format

Ranides Atterwim 10 years ago
parent
commit
00317dc5d9

+ 0 - 3
assira/pom.xml

@@ -64,9 +64,6 @@
                                 <include>net/ranides/assira/text/LexicalCast*</include>
                                 <include>net/ranides/assira/text/StringIO*</include>
                                 <include>net/ranides/assira/text/format/**</include>
-                                <include>net/ranides/assira/text/ResolveUtils**</include>
-                                <include>net/ranides/assira/text/ResolveFormat**</include>
-                                <include>net/ranides/assira/text/ResolveDialect**</include>
                                 
                                 <include>net/ranides/assira/xml/XMLQuery*</include>
                                 <include>net/ranides/assira/xml/XMLWriter*</include>

+ 4 - 0
assira/src/main/java/net/ranides/assira/text/FormatNumber.java

@@ -197,6 +197,10 @@ public final class FormatNumber {
             this.dv = BigDecimal.valueOf(v);
             this.u = u;
         }
+        
+        public long longValue() {
+            return (long)v;
+        }
 
         public double doubleValue() {
             return v;

+ 4 - 4
assira/src/main/java/net/ranides/assira/text/LexicalCast.java

@@ -11,15 +11,12 @@ import java.io.IOException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.fasterxml.jackson.databind.type.TypeFactory;
-import java.time.DateTimeException;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
-import java.time.ZonedDateTime;
-import java.time.temporal.ChronoField;
 import java.time.temporal.TemporalAccessor;
-import java.time.temporal.TemporalField;
 import java.util.Date;
+import net.ranides.assira.reflection.IArguments;
 import net.ranides.assira.reflection.IClass;
 
 /**
@@ -172,6 +169,9 @@ public final class LexicalCast {
                 return ((Date)value).getTime();
             }
         }
+        if(!type.constructors().accepts(value).isEmpty()) {
+            return type.construct(value);
+        }
         return LexicalCast.fromJSON(LexicalCast.toJSON(value), type);
     }
     

+ 71 - 22
assira/src/main/java/net/ranides/assira/text/ResolveDialect.java

@@ -9,14 +9,7 @@ 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.ParseException;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
+import java.text.*;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
@@ -26,6 +19,8 @@ import java.util.Locale;
 import java.util.Map;
 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;
@@ -34,7 +29,6 @@ import net.ranides.assira.generic.ValueUtils;
 import net.ranides.assira.reflection.IAttribute;
 import net.ranides.assira.reflection.IClass;
 import net.ranides.assira.reflection.Resolver;
-import static net.ranides.assira.text.FormatNumber.MP;
 import net.ranides.assira.text.FormatNumber.UnitPrefix;
 
 /**
@@ -49,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());
     
     }
     
@@ -265,6 +259,7 @@ public final class ResolveDialect {
 
         @Override
         public final void parse(String source, Object context) throws ParseException {
+//            iresolver.type(context)
             set(context, parse(source));
         }
         
@@ -406,13 +401,15 @@ public final class ResolveDialect {
     
     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-9]{2}?)?(?:,0x[0-9]{2})*\\})";
+            return "(\\[[0-9]+\\]\\{(?:0x[0-9a-fA-F]{2}?)?(?:,0x[0-9a-fA-F]{2})*\\})";
         }
 
         @Override
@@ -439,9 +436,20 @@ public final class ResolveDialect {
         }
 
         @Override
-        public Object parse(String source) {
-            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;
         }
+        
 
     }
     
@@ -453,7 +461,7 @@ public final class ResolveDialect {
         
         @Override
         public String regex() {
-            return "((?:[0-9A-F]{2})?(?: [0-9A-F]{2})*)";
+            return "((?:[0-9A-Fa-f]{2})?(?: [0-9A-Fa-f]{2})*)";
         }
 
         @Override
@@ -474,30 +482,41 @@ public final class ResolveDialect {
 
         @Override
         public Object parse(String source) {
-            throw new UnsupportedOperationException("Not supported yet.");
+            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 "([0-9,]+(?:\\.[0-9,]+)?(?:" + StringUtils.join(MP, "|", b -> b.text()) + "))";
+            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) {
@@ -524,10 +543,40 @@ public final class ResolveDialect {
         }
 
         @Override
-        public Object parse(String source) {
-            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('-');

+ 19 - 0
assira/src/test/java/net/ranides/assira/text/LexicalCastTest.java

@@ -56,6 +56,11 @@ public class LexicalCastTest {
         assertEquals(3.14, LexicalCast.cast(3.14f, Double.class), 0.001);
     }
     
+    @Test
+    public void testStringConstructor() {
+        assertEquals("[ranides]", LexicalCast.cast("ranides", Name.class).name());
+    }
+    
     private static Short asShort(int value) {
         return (short)value;
     }
@@ -63,4 +68,18 @@ public class LexicalCastTest {
     private static Byte asByte(int value) {
         return (byte)value;
     }
+    
+    private static final class Name {
+        
+        private final String mName;
+
+        public Name(String iname) {
+            this.mName = "[" + iname + "]";
+        }
+
+        public String name() {
+            return mName;
+        }
+        
+    }
 }

+ 97 - 11
assira/src/test/java/net/ranides/assira/text/ResolveFormatTest.java

@@ -10,11 +10,11 @@ import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
 import java.math.BigInteger;
-import java.text.ChoiceFormat;
 import java.time.Instant;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.GregorianCalendar;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import net.ranides.assira.generic.HashUtils;
@@ -90,7 +90,7 @@ public class ResolveFormatTest {
         assertEquals("-150_456.5",    ResolveFormat.compile("{fvalue,number,java}").format(ITEM) );
         assertEquals("-150'456.5",    ResolveFormat.compile("{fvalue,number,c++}").format(ITEM) );
     }
-    
+        
     @Test
     public void testParse_Errors() {
         Integer[] out= new Integer[3];
@@ -108,8 +108,7 @@ public class ResolveFormatTest {
     @Test
     public void testParse_Number() {
         Integer[] out= new Integer[3];
-        ResolveFormat rf = ResolveFormat.compile("{0,number} / {1,number,java} / {2,number,java}");
-        rf.parse("12 / 33 / 55_100", out);
+        ResolveFormat.compile("{0,number} / {1,number,java} / {2,number,java}").parse("12 / 33 / 55_100", out);
         assertArrayEquals(new Integer[]{12,33,55100}, out);
         
         Double[] out2= new Double[3];
@@ -230,12 +229,30 @@ public class ResolveFormatTest {
     }
     
     @Test
-    public void testHexArray() {
+    public void testFormat_HexArray() {
         assertEquals("hex = [4]{7A,0x31,0x45,0xAC}", ResolveFormat.compile("hex = {data1,hex}").format(ITEM) );
         assertEquals("hex = [4]{7A,0x31,0x45,0xAC}", ResolveFormat.compile("hex = {data1,hex,array}").format(ITEM) );
         assertEquals("hex = 7A 31 45 AC", ResolveFormat.compile("hex = {data1,hex,stream}").format(ITEM) );
     }
     
+    @Test
+    public void testParse_HexArray() {
+        BData out1 = new BData();
+        ResolveFormat.compile("array = {value,hex,array}x").parse("array = [3]{0x10,0x3C,0x3A}x", out1);
+        assertArrayEquals(new byte[]{0x10,0x3C,0x3A}, out1.value);
+        
+        BData out2 = new BData();
+        ResolveFormat.compile("array = {value,hex,stream}B").parse("array = 10 3C 3AB", out2);
+        assertArrayEquals(new byte[]{0x10,0x3C,0x3A}, out2.value);
+    }
+    
+    @Test
+    public void testParse_Generic() {
+        String out[] = new String[3];
+        ResolveFormat.compile("{0} / {1} / last = {2}.").parse("hello / world / last = 23.", out);
+        assertArrayEquals(new String[]{"hello","world","23"}, out);
+    }
+    
     @Test
     public void testFormat_Metric_Int() {
         assertEquals("-154.27k", ResolveFormat.compile("{ivalue,metric}").format(ITEM));
@@ -291,6 +308,61 @@ public class ResolveFormatTest {
         assertEquals("-154.200E3", ResolveFormat.compile("{bivalue,metric/e,#.000}").format(ITEM));
     }
     
+    @Test
+    public void testParse_MetricSI() {
+        NumData out = new NumData();
+        ResolveFormat.compile("{iv,metric/si}!").parse("12k!", out);
+        assertEquals(12000, out.iv);
+        
+        ResolveFormat.compile("{iv,metric/si}!").parse("12!", out);
+        assertEquals(12, out.iv);
+        
+        ResolveFormat.compile("{dv,metric/si}!").parse("12.5M!", out);
+        assertEquals(12500000.0, out.dv, 0.1);
+        
+        ResolveFormat.compile("{dv,metric/si}!").parse("12.5372!", out);
+        assertEquals(12.5372, out.dv, 0.00001);
+        
+        ResolveFormat.compile("{bd,metric/si}!").parse("125k!", out);
+        assertTrue(0 == new BigDecimal("125000").compareTo(out.bd));
+        
+        ResolveFormat.compile("{bd,metric/si}!").parse("12.5372!", out);
+        assertTrue(0 == new BigDecimal("12.5372").compareTo(out.bd));
+        
+        ResolveFormat.compile("{bi,metric/si}!").parse("127k!", out);
+        assertTrue(0 == new BigInteger("127000").compareTo(out.bi));
+        
+        ResolveFormat.compile("{bi,metric/si}!").parse("19!", out);
+        assertTrue(0 == new BigInteger("19").compareTo(out.bi));
+    }
+    
+    @Test
+    public void testParse_MetricBinaryIEC() {
+        NumData out = new NumData();
+        ResolveFormat.compile("{iv,binary/iec}!").parse("12Ki!", out);
+        assertEquals(12*1024, out.iv);
+        
+        ResolveFormat.compile("{iv,binary/iec}!").parse("12!", out);
+        assertEquals(12, out.iv);
+        
+        ResolveFormat.compile("{dv,binary/iec}!").parse("12.5Mi!", out);
+        assertEquals(12.5*1024.0*1024.0, out.dv, 0.1);
+        
+        ResolveFormat.compile("{dv,binary/iec}!").parse("12.5372!", out);
+        assertEquals(12.5372, out.dv, 0.00001);
+        
+        ResolveFormat.compile("{bd,binary/iec}!").parse("125Ki!", out);
+        assertTrue(0 == new BigDecimal("128000").compareTo(out.bd));
+        
+        ResolveFormat.compile("{bd,binary/iec}!").parse("12.5372!", out);
+        assertTrue(0 == new BigDecimal("12.5372").compareTo(out.bd));
+        
+        ResolveFormat.compile("{bi,binary/iec}!").parse("127Ki!", out);
+        assertTrue(0 == new BigInteger("130048").compareTo(out.bi));
+        
+        ResolveFormat.compile("{bi,binary/iec}!").parse("19!", out);
+        assertTrue(0 == new BigInteger("19").compareTo(out.bi));
+    }
     
     @Test
     public void testFormat_Binary_Int() {
@@ -441,12 +513,6 @@ public class ResolveFormatTest {
         
     }
     
-    
-    // @todo (assira #0) test: ResolveFormat# parse FHexArray 
-    // @todo (assira #0) test: ResolveFormat# parse FHexStream  
-    // @todo (assira #0) test: ResolveFormat# parse FEngineer   
-    // @todo (assira #0) test: ResolveFormat# parse FGeneric    
-    
     private static final Object ITEM = new Object(){
     
         public float value1 = 3.1415f;
@@ -470,5 +536,25 @@ public class ResolveFormatTest {
         public BigInteger value128 = new BigInteger("-1542000000000000000000000");
         
     };
+    
+    private static final class BData {
+        
+        public byte[] value;
+        
+    }
+    
+    private static final class NumData {
+        
+        public BigDecimal bd;
+        
+        public BigInteger bi;
+        
+        public AtomicInteger ai;
+        
+        public double dv;
+        
+        public long iv;
+        
+    }
 
 }

+ 6 - 0
assira/src/test/java/net/ranides/assira/text/ResolveUtilsTest.java

@@ -61,4 +61,10 @@ public class ResolveUtilsTest {
         assertEquals("r3 = Hello 17 world!", r3.toString());
     }
     
+    @Test
+    public void testParse() {
+        int[] out = new int[2];
+        ResolveUtils.parse("{0,number} / {1,number}", "7 / 9", out);
+        assertArrayEquals(new int[]{7,9}, out);
+    }
 }