Skip to content

Commit cca0a95

Browse files
committed
JSON and data type updates
1 parent 96637cf commit cca0a95

File tree

15 files changed

+199
-133
lines changed

15 files changed

+199
-133
lines changed

convex-core/src/main/antlr4/convex/core/json/reader/antlr/JSON5.g4

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ pair
2222

2323
key
2424
: string
25+
| identifier
26+
;
27+
28+
identifier
29+
: IDENTIFIER
2530
;
2631

2732
// Note single training comma allowed after values
@@ -48,7 +53,7 @@ string
4853

4954
// numbers allow extra IEEE754 values as per JSON5
5055
number
51-
: NUMBER | 'NaN' | 'Infinity' | '+Infinity' | '-Infinity';
56+
: NUMBER | NUMERIC_LITERAL | '+Infinity' | '-Infinity';
5257

5358
nil
5459
: 'null';
@@ -74,7 +79,43 @@ fragment SAFECODEPOINT
7479
;
7580

7681
NUMBER
77-
: '-'? INT ('.' [0-9]+)? EXP?
82+
: SYMBOL? INT ('.' [0-9]+)? EXP?
83+
| SYMBOL? '.' [0-9]+ EXP?
84+
;
85+
86+
NUMERIC_LITERAL
87+
: SYMBOL? 'Infinity'
88+
| 'NaN'
89+
;
90+
91+
IDENTIFIER
92+
: IDENTIFIER_START IDENTIFIER_PART*
93+
;
94+
95+
fragment IDENTIFIER_START
96+
: [\p{L}]
97+
| '$'
98+
| '_'
99+
| '\\' UNICODE
100+
;
101+
102+
fragment IDENTIFIER_PART
103+
: IDENTIFIER_START
104+
| [\p{M}]
105+
| [\p{N}]
106+
| [\p{Pc}]
107+
| '\u200C'
108+
| '\u200D'
109+
;
110+
111+
fragment SYMBOL
112+
: '+'
113+
| '-'
114+
;
115+
116+
fragment NEWLINE
117+
: '\r\n'
118+
| [\r\n\u2028\u2029]
78119
;
79120

80121
fragment INT

convex-core/src/main/java/convex/core/cpos/Belief.java

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
import convex.core.data.AVector;
1414
import convex.core.data.AccountKey;
1515
import convex.core.data.Blob;
16-
import convex.core.data.Cells;
17-
import convex.core.data.Hash;
1816
import convex.core.data.Index;
1917
import convex.core.data.Keyword;
2018
import convex.core.data.SignedData;
@@ -176,30 +174,6 @@ public Index<AccountKey, SignedData<Order>> getOrders() {
176174
if (orders==null) orders=(Index<AccountKey, SignedData<Order>>) values.get(0);
177175
return orders;
178176
}
179-
180-
@Override
181-
public boolean equals(ACell a) {
182-
if (a instanceof Belief) return equals((Belief)a);
183-
return super.equals(a);
184-
}
185-
186-
/**
187-
* Tests if this Belief is equal to another
188-
* @param a Belief to compare with
189-
* @return true if equal, false otherwise
190-
*/
191-
public boolean equals(Belief a) {
192-
if (this == a) return true; // important optimisation for e.g. hashmap equality
193-
if (a == null) return false;
194-
Hash h=this.cachedHash();
195-
if (h!=null) {
196-
Hash ha=a.cachedHash();
197-
if (ha!=null) return Cells.equals(h, ha);
198-
}
199-
200-
if (!getOrders().equals(a.getOrders())) return false;
201-
return true;
202-
}
203177

204178
/**
205179
* Gets a new HashMap containing all Orders

convex-core/src/main/java/convex/core/data/prim/ANumeric.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package convex.core.data.prim;
22

3+
import java.math.BigDecimal;
4+
import java.math.BigInteger;
5+
36
/**
47
* BAse class for CVM numeric types
58
*/
@@ -84,4 +87,36 @@ public abstract class ANumeric extends APrimitive implements Comparable<ANumeric
8487
* @return True if this value is numerically equal to zero
8588
*/
8689
public abstract boolean isZero();
90+
91+
92+
@SuppressWarnings("unchecked")
93+
public static <T extends ANumeric> T fromNumber(Number number) {
94+
if (number == null) {
95+
return null;
96+
}
97+
98+
// Fast paths for common types
99+
if (number instanceof Long || number instanceof Integer || number instanceof Short || number instanceof Byte) {
100+
return (T) CVMLong.create(number.longValue());
101+
}
102+
if (number instanceof Double || number instanceof Float) {
103+
return (T) CVMDouble.create(number.doubleValue());
104+
}
105+
106+
if (number instanceof BigInteger bi) {
107+
return (T) AInteger.create(bi);
108+
}
109+
110+
// Slow path for other Number subclasses (e.g., AtomicInteger, AtomicLong)
111+
try {
112+
BigDecimal bd = new BigDecimal(number.toString());
113+
BigInteger bi = bd.toBigIntegerExact();
114+
if (bi.bitLength() <= 63) {
115+
return (T) CVMLong.create(bi.longValue());
116+
}
117+
return (T) CVMBigInteger.create(bi);
118+
} catch (ArithmeticException | NumberFormatException e) {
119+
return (T) CVMDouble.create(number.doubleValue());
120+
}
121+
}
87122
}

convex-core/src/main/java/convex/core/init/Init.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,8 +488,8 @@ private static State doCurrencyDeploy(State s, AVector<ACell> row) {
488488
String symName = row.get(0).toString();
489489
String name = row.get(1).toString();
490490
String desc = row.get(2).toString();
491-
double usdPrice = RT.jvm(row.get(6)); // Value in USD for currency, e.g. USD=1.0, GBP=1.3
492-
long decimals = RT.jvm(row.get(5)); // Decimals for lowest currency unit, e.g. USD = 2
491+
double usdPrice = (Double) RT.jvm(row.get(6)); // Value in USD for currency, e.g. USD=1.0, GBP=1.3
492+
long decimals = (Long) RT.jvm(row.get(5)); // Decimals for lowest currency unit, e.g. USD = 2
493493
long usdValue=(Long) RT.jvm(row.get(4)); // USD value of liquidity in currency
494494

495495
// number of sub-units in currency

convex-core/src/main/java/convex/core/json/JSON5Reader.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ public void exitString(StringContext ctx) {
107107
push(JSONUtils.unescape(content));
108108
}
109109

110+
@Override
111+
public void exitIdentifier(IdentifierContext ctx) {
112+
String text=ctx.getText();
113+
// no need to take substring, should be full identifier name
114+
push(JSONUtils.unescape(text));
115+
}
116+
110117
@Override
111118
public void enterObj(ObjContext ctx) {
112119
pushList(); // We add a new ArrayList to the stack to capture values

convex-core/src/main/java/convex/core/lang/RT.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,26 +1789,24 @@ public static <T extends ACell> T cvm(Object o) {
17891789
return null;
17901790
if (o instanceof ACell)
17911791
return ((T) o);
1792-
if (o instanceof String)
1793-
return (T) Strings.create((String) o);
1794-
if (o instanceof Double)
1795-
return (T) CVMDouble.create(((Double) o));
1796-
if (o instanceof Number)
1797-
return (T) CVMLong.create(((Number) o).longValue());
1798-
if (o instanceof Character)
1799-
return (T) CVMChar.create((Character) o);
1800-
if (o instanceof Boolean)
1801-
return (T) CVMBool.create((Boolean) o);
1802-
if (o instanceof List) {
1803-
List<?> l = (List<?>) o;
1792+
if (o instanceof String s)
1793+
return (T) Strings.create(s);
1794+
if (o instanceof Double d)
1795+
return (T) CVMDouble.create(d);
1796+
if (o instanceof Number n)
1797+
return (T) ANumeric.fromNumber(n);
1798+
if (o instanceof Character c)
1799+
return (T) CVMChar.create(c);
1800+
if (o instanceof Boolean b)
1801+
return (T) CVMBool.create(b);
1802+
if (o instanceof List l) {
18041803
AVector<?> v = Vectors.empty();
18051804
for (Object val : l) {
18061805
v = v.conj(cvm(val));
18071806
}
18081807
return (T) v;
18091808
}
1810-
if (o instanceof Map) {
1811-
Map<?, ?> m = (Map<?, ?>) o;
1809+
if (o instanceof Map<?,?> m) {
18121810
AMap<ACell, ACell> cm = Maps.empty();
18131811
for (Map.Entry<?, ?> me : m.entrySet()) {
18141812
Object k = me.getKey();
@@ -1833,6 +1831,8 @@ public static <T extends ACell> T cvm(Object o) {
18331831

18341832
throw new IllegalArgumentException("Can't convert to CVM type with class: " + Utils.getClassName(o));
18351833
}
1834+
1835+
18361836

18371837
/**
18381838
* Converts a CVM value to equivalent JVM value
@@ -1847,7 +1847,7 @@ public static <T> T jvm(ACell o) {
18471847
if (o instanceof CVMLong)
18481848
return (T) (Long) ((CVMLong) o).longValue();
18491849
if (o instanceof CVMDouble)
1850-
return (T) (Double) ((CVMDouble) o).doubleValue();
1850+
return (T) (Double) ((CVMDouble) o).doubleValue();
18511851
if (o instanceof CVMBool)
18521852
return (T) (Boolean) ((CVMBool) o).booleanValue();
18531853
if (o instanceof CVMChar)

convex-core/src/main/java/convex/core/util/JSONUtils.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import convex.core.data.MapEntry;
2121
import convex.core.data.StringShort;
2222
import convex.core.data.Strings;
23+
import convex.core.data.prim.CVMBigInteger;
2324
import convex.core.data.prim.CVMBool;
2425
import convex.core.data.prim.CVMChar;
2526
import convex.core.data.prim.CVMDouble;
@@ -49,23 +50,24 @@ public class JSONUtils {
4950
* @param o Value to convert to JSON value object
5051
* @return Java Object which represents JSON value
5152
*/
52-
@SuppressWarnings("unchecked")
53-
public static <T> T json(ACell o) {
53+
public static Object json(ACell o) {
5454
if (o == null)
5555
return null;
5656
if (o instanceof CVMLong)
57-
return (T) (Long) ((CVMLong) o).longValue();
57+
return ((CVMLong) o).longValue();
58+
if (o instanceof CVMBigInteger)
59+
return ((CVMBigInteger) o).big();
5860
if (o instanceof CVMDouble)
59-
return (T) (Double) ((CVMDouble) o).doubleValue();
61+
return ((CVMDouble) o).doubleValue();
6062
if (o instanceof CVMBool)
61-
return (T) (Boolean) ((CVMBool) o).booleanValue();
63+
return ((CVMBool) o).booleanValue();
6264
if (o instanceof CVMChar)
63-
return (T) ((CVMChar) o).toString();
65+
return ((CVMChar) o).toString();
6466
if (o instanceof Address)
65-
return (T) (Long) ((Address) o).longValue();
67+
return (Long) ((Address) o).longValue();
6668
if (o instanceof AMap) {
6769
AMap<?, ?> m = (AMap<?, ?>) o;
68-
return (T) JSONUtils.jsonMap(m);
70+
return JSONUtils.jsonMap(m);
6971
}
7072
if (o instanceof ASequence) {
7173
ASequence<?> seq = (ASequence<?>) o;
@@ -76,10 +78,10 @@ public static <T> T json(ACell o) {
7678
Object v = json(cvmv);
7779
list.add(v);
7880
}
79-
return (T) list;
81+
return list;
8082
}
8183

82-
return (T) o.toString();
84+
return o.toString();
8385
}
8486

8587
/**
@@ -131,7 +133,7 @@ public static HashMap<String, Object> jsonMap(AMap<?, ?> m) {
131133
}
132134

133135
/**
134-
* Convert any object to JSON
136+
* Convert any object to a String containing valid JSON
135137
*
136138
* @param value Value to convert to JSON, may be Java or CVM structure
137139
* @return Java String containing valid JSON String
@@ -322,6 +324,11 @@ private static void appendJSON(BlobBuilder bb, ACell value) {
322324
return;
323325
}
324326

327+
if (value instanceof CVMBigInteger nv) {
328+
bb.append(nv.toString());
329+
return;
330+
}
331+
325332
if (value instanceof CVMBool bv) {
326333
bb.append(bv.booleanValue() ? Strings.TRUE : Strings.FALSE);
327334
return;

convex-core/src/test/java/convex/actors/TorusTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ public class TorusTest extends ACVMTest {
334334
// FIRST TEST: Initial deposit of $100k USD liquidity
335335
// Deposit some liquidity $100,000 for 1000 Gold = $100 price = 100000 CVX / US Cent
336336
ctx= exec(ctx,"(call USDM 1000000000000 (add-liquidity 10000000))");
337-
final long INITIAL_SHARES=RT.jvm(ctx.getResult());
337+
final long INITIAL_SHARES=(Long)RT.jvm(ctx.getResult());
338338

339339
assertEquals(10000000L,evalL(ctx,"(asset/balance USD USDM)"));
340340
assertEquals(1000000000000L,evalL(ctx,"(balance USDM)"));
@@ -350,7 +350,7 @@ public class TorusTest extends ACVMTest {
350350
// SECOND TEST: Initial deposit of $100k USD liquidity
351351
// Deposit more liquidity $100,000 for 1000 Gold - previous token offer should cover this
352352
ctx= exec(ctx,"(call USDM 1000000000000 (add-liquidity 10000000))");
353-
final long NEW_SHARES=RT.jvm(ctx.getResult());
353+
final long NEW_SHARES=(Long) RT.jvm(ctx.getResult());
354354
assertEquals(20000000L,evalL(ctx,"(asset/balance USD USDM)"));
355355

356356
// Check new pool shares, accessible as a fungible asset balance
@@ -380,7 +380,7 @@ public class TorusTest extends ACVMTest {
380380
// ============================================================
381381
// FORTH TEST - buy half of all tokens ($50k)
382382
ctx= step(ctx,"(call USDM *balance* (buy-tokens 5000000))");
383-
long paidConvex=RT.jvm(ctx.getResult());
383+
long paidConvex=(Long) RT.jvm(ctx.getResult());
384384
assertTrue(paidConvex>1000000000000L); // should cost more than pool Convex balance after fee
385385
assertTrue(paidConvex<1100000000000L,"Paid:" +paidConvex); // but less than 10% fee
386386
assertEquals(5000000L,evalL(ctx,"(asset/balance USD USDM)"));
@@ -391,7 +391,7 @@ public class TorusTest extends ACVMTest {
391391
// FIFTH TEST - sell back tokens ($50k)
392392
ctx= step(ctx,"(asset/offer USDM [USD 5000000])");
393393
ctx= step(ctx,"(call USDM (sell-tokens 5000000))");
394-
long gainedConvex=RT.jvm(ctx.getResult());
394+
long gainedConvex=(Long)RT.jvm(ctx.getResult());
395395
assertTrue(gainedConvex>900000000000L); // should gain most of money back
396396
assertTrue(gainedConvex<paidConvex,"Gain:" +gainedConvex); // but less than cost, since we have fees
397397
assertEquals( 10000000L,evalL(ctx,"(asset/balance USD USDM)"));

convex-core/src/test/java/convex/core/data/AdversarialDataTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ public class AdversarialDataTest {
172172
invalidEncoding(Tag.SYMBOL,"00");
173173
}
174174

175+
@Test
176+
public void testRegressions() throws BadFormatException {
177+
invalidTest(Format.read("d401120090"));
178+
}
179+
175180
@Test
176181
public void testDummy() {
177182
invalidTest(Cells.DUMMY);

convex-core/src/test/java/convex/core/data/prim/BigIntegerTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ public class BigIntegerTest {
8787
doBigTest(bi);
8888
}
8989

90+
@Test public void testEdgeCaseBigInteger() {
91+
BigInteger bi =new BigInteger("-9223372036854775809");
92+
assertEquals(CVMBigInteger.create(bi),ANumeric.fromNumber(bi));
93+
}
94+
9095
@Test public void testMemorySize() {
9196
int N=1000;
9297
byte[] bs=new byte[N];

0 commit comments

Comments
 (0)