mirror of
https://github.com/zeroflag/fcl.git
synced 2025-01-11 20:01:10 +01:00
wip
This commit is contained in:
parent
bb5e19461b
commit
43b718d1a7
7 changed files with 190 additions and 55 deletions
|
@ -9,7 +9,7 @@ import java.util.Map;
|
|||
|
||||
import static com.vectron.fcl.Fcl.STRICT;
|
||||
|
||||
public class Dic implements Obj {
|
||||
public class Dic implements Obj, Iterable<Lst> {
|
||||
private final Map<Obj, Obj> value = new LinkedHashMap<>();
|
||||
|
||||
public static Dic empty() {
|
||||
|
@ -70,6 +70,7 @@ public class Dic implements Obj {
|
|||
return Bool.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Lst> iterator() {
|
||||
return new Iterator<Lst>() {
|
||||
private Iterator<Map.Entry<Obj,Obj>> it = value.entrySet().iterator();
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
|
||||
import static com.vectron.fcl.Fcl.STRICT;
|
||||
|
||||
public class Lst implements Obj, ArithmeticOperand {
|
||||
public class Lst implements Obj, ArithmeticOperand, Iterable<Obj> {
|
||||
private final List<Obj> value = new ArrayList<>();
|
||||
|
||||
public static Lst empty() {
|
||||
|
@ -76,10 +76,6 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
return value.get(index.intValue());
|
||||
}
|
||||
|
||||
private Obj atIfAbsent(int index, Obj defaultValue) {
|
||||
return index < size() ? value.get(index) : defaultValue;
|
||||
}
|
||||
|
||||
public int indexOf(Obj item) {
|
||||
return value.indexOf(item);
|
||||
}
|
||||
|
@ -114,6 +110,7 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
return Bool.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Obj> iterator() {
|
||||
return value.iterator();
|
||||
}
|
||||
|
@ -166,11 +163,13 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
for (Obj each : value)
|
||||
result.append(Fcl.aOp(each).add(other));
|
||||
return result;
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (int i = 0; i < Math.max(size(), ((Lst) other).size()); i++) {
|
||||
Obj a = atIfAbsent(i, Num.ZERO);
|
||||
Obj b = ((Lst)other).atIfAbsent(i, Num.ZERO);
|
||||
Iterator<Obj> it1 = this.iterator();
|
||||
Iterator<Obj> it2 = ((Iterable<Obj>) other).iterator();
|
||||
while (it1.hasNext() || it2.hasNext()) {
|
||||
Obj a = it1.hasNext() ? it1.next() : Num.ZERO;
|
||||
Obj b = it2.hasNext() ? it2.next() : Num.ZERO;
|
||||
result.append(Fcl.aOp(a).add(b));
|
||||
}
|
||||
return result;
|
||||
|
@ -186,11 +185,13 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
for (Obj each : value)
|
||||
result.append(Fcl.aOp(each).sub(other));
|
||||
return result;
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (int i = 0; i < Math.max(size(), ((Lst) other).size()); i++) {
|
||||
Obj a = atIfAbsent(i, Num.ZERO);
|
||||
Obj b = ((Lst)other).atIfAbsent(i, Num.ZERO);
|
||||
Iterator<Obj> it1 = this.iterator();
|
||||
Iterator<Obj> it2 = ((Iterable<Obj>) other).iterator();
|
||||
while (it1.hasNext() || it2.hasNext()) {
|
||||
Obj a = it1.hasNext() ? it1.next() : Num.ZERO;
|
||||
Obj b = it2.hasNext() ? it2.next() : Num.ZERO;
|
||||
result.append(Fcl.aOp(a).sub(b));
|
||||
}
|
||||
return result;
|
||||
|
@ -206,11 +207,13 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
for (Obj each : value)
|
||||
result.append(Fcl.aOp(each).mul(other));
|
||||
return result;
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (int i = 0; i < Math.max(size(), ((Lst) other).size()); i++) {
|
||||
Obj a = atIfAbsent(i, Num.ONE);
|
||||
Obj b = ((Lst)other).atIfAbsent(i, Num.ONE);
|
||||
Iterator<Obj> it1 = this.iterator();
|
||||
Iterator<Obj> it2 = ((Iterable<Obj>) other).iterator();
|
||||
while (it1.hasNext() || it2.hasNext()) {
|
||||
Obj a = it1.hasNext() ? it1.next() : Num.ONE;
|
||||
Obj b = it2.hasNext() ? it2.next() : Num.ONE;
|
||||
result.append(Fcl.aOp(a).mul(b));
|
||||
}
|
||||
return result;
|
||||
|
@ -226,12 +229,14 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
for (Obj each : value)
|
||||
result.append(Fcl.aOp(each).div(other));
|
||||
return result;
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (int i = 0; i < Math.max(size(), ((Lst) other).size()); i++) {
|
||||
Obj a = atIfAbsent(i, Num.ZERO);
|
||||
Obj b = ((Lst)other).atIfAbsent(i, Num.ONE);
|
||||
result.append((Fcl.aOp(a)).div(b));
|
||||
Iterator<Obj> it1 = this.iterator();
|
||||
Iterator<Obj> it2 = ((Iterable<Obj>) other).iterator();
|
||||
while (it1.hasNext() || it2.hasNext()) {
|
||||
Obj a = it1.hasNext() ? it1.next() : Num.ZERO;
|
||||
Obj b = it2.hasNext() ? it2.next() : Num.ONE;
|
||||
result.append(Fcl.aOp(a).div(b));
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
|
@ -246,11 +251,13 @@ public class Lst implements Obj, ArithmeticOperand {
|
|||
for (Obj each : value)
|
||||
result.append(Fcl.aOp(each).pow(other));
|
||||
return result;
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (int i = 0; i < Math.max(size(), ((Lst) other).size()); i++) {
|
||||
Obj a = atIfAbsent(i, Num.ONE);
|
||||
Obj b = ((Lst)other).atIfAbsent(i, Num.ONE);
|
||||
Iterator<Obj> it1 = this.iterator();
|
||||
Iterator<Obj> it2 = ((Iterable<Obj>) other).iterator();
|
||||
while (it1.hasNext() || it2.hasNext()) {
|
||||
Obj a = it1.hasNext() ? it1.next() : Num.ONE;
|
||||
Obj b = it2.hasNext() ? it2.next() : Num.ONE;
|
||||
result.append(Fcl.aOp(a).pow(b));
|
||||
}
|
||||
return result;
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.vectron.fcl.exceptions.TypeMismatched;
|
|||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -76,8 +77,8 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|||
return new Num((Double) value + (Long)other.value());
|
||||
else if (value instanceof Double && other.value() instanceof Double)
|
||||
return new Num((Double) value + (Double) other.value());
|
||||
else if (other instanceof Lst)
|
||||
return ((Lst) other).add(this);
|
||||
else if (other instanceof ArithmeticOperand && !(other instanceof Num))
|
||||
return ((ArithmeticOperand) other).add(this);
|
||||
else if (STRICT)
|
||||
throw new TypeMismatched("+", this, other);
|
||||
return Num.NAN;
|
||||
|
@ -93,8 +94,8 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|||
return new Num((Double) value - (Long)other.value());
|
||||
else if (value instanceof Double && other.value() instanceof Double)
|
||||
return new Num((Double) value - (Double) other.value());
|
||||
else if (other instanceof Lst)
|
||||
return ((Lst) other).mul(Num.MINUS_ONE).add(this);
|
||||
else if (other instanceof ArithmeticOperand && !(other instanceof Num))
|
||||
return ((ArithmeticOperand)((ArithmeticOperand) other).mul(Num.MINUS_ONE)).add(this);
|
||||
else if (STRICT)
|
||||
throw new TypeMismatched("-", this, other);
|
||||
return Num.NAN;
|
||||
|
@ -110,10 +111,8 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|||
return new Num((Double) value * (Long)other.value());
|
||||
else if (value instanceof Double && other.value() instanceof Double)
|
||||
return new Num((Double) value * (Double) other.value());
|
||||
else if (other instanceof Lst)
|
||||
return ((Lst) other).mul(this);
|
||||
else if (other instanceof Str)
|
||||
return ((Str) other).mul(this);
|
||||
else if (other instanceof ArithmeticOperand && !(other instanceof Num))
|
||||
return ((ArithmeticOperand) other).mul(this);
|
||||
else if (STRICT)
|
||||
throw new TypeMismatched("*", this, other);
|
||||
return Num.NAN;
|
||||
|
@ -129,8 +128,8 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|||
return new Num((Double) value / (Long)other.value());
|
||||
else if (value instanceof Double && other.value() instanceof Double)
|
||||
return new Num((Double) value / (Double) other.value());
|
||||
else if (other instanceof Lst)
|
||||
return ((ArithmeticOperand) ((Lst) other).pow(Num.MINUS_ONE)).mul(this);
|
||||
else if (other instanceof ArithmeticOperand && !(other instanceof Num))
|
||||
return ((ArithmeticOperand) ((ArithmeticOperand) other).pow(Num.MINUS_ONE)).mul(this);
|
||||
else if (STRICT)
|
||||
throw new TypeMismatched("/", this, other);
|
||||
return Num.NAN;
|
||||
|
@ -140,10 +139,11 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
|||
public Obj pow(Obj other) {
|
||||
if (other instanceof Num) {
|
||||
return new Num(Math.pow(doubleValue(), other.doubleValue()));
|
||||
} else if (other instanceof Lst) {
|
||||
} else if (other.iterable().boolValue()) {
|
||||
Lst result = Lst.empty();
|
||||
for (Obj each : ((Lst) other).value())
|
||||
result.append(this.pow(each));
|
||||
Iterator<Obj> it = ((Iterable)other).iterator();
|
||||
while (it.hasNext())
|
||||
result.append(this.pow(it.next()));
|
||||
return result;
|
||||
} else if (STRICT) {
|
||||
throw new TypeMismatched("pow", this, other);
|
||||
|
|
|
@ -7,12 +7,10 @@ import java.util.Iterator;
|
|||
|
||||
import static com.vectron.fcl.Fcl.STRICT;
|
||||
|
||||
public class Range implements Obj {
|
||||
private RangeIterator iterator;
|
||||
public class Range implements Obj, Iterable<Obj>, ArithmeticOperand {
|
||||
private final Num from;
|
||||
private final Num to;
|
||||
private final Num by;
|
||||
private Num current;
|
||||
|
||||
public static Range create(Num by, Num to, Num from) {
|
||||
return new Range(from, to, by);
|
||||
|
@ -24,7 +22,6 @@ public class Range implements Obj {
|
|||
this.from = from;
|
||||
this.to = to;
|
||||
this.by = by;
|
||||
this.current = from;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,22 +60,21 @@ public class Range implements Obj {
|
|||
return Bool.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Obj> iterator() {
|
||||
if (iterator == null)
|
||||
iterator = new RangeIterator();
|
||||
return iterator;
|
||||
return new RangeIterator(from, to, by);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return by.doubleValue() == 1
|
||||
? String.format("%s..%s (%s)", from, to, current)
|
||||
: String.format("%s...%s (%s) by %s", from, to, current, by);
|
||||
? String.format("%s..%s", from, to)
|
||||
: String.format("%s..%s by %s", from, to, by);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object value() {
|
||||
return iterator;
|
||||
return new RangeIterator(from, to, by);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -91,7 +87,50 @@ public class Range implements Obj {
|
|||
return -1;
|
||||
}
|
||||
|
||||
public class RangeIterator implements Iterator<Obj> {
|
||||
@Override
|
||||
public Obj add(Obj other) {
|
||||
return toLst().add(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Obj sub(Obj other) {
|
||||
return toLst().sub(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Obj mul(Obj other) {
|
||||
return toLst().mul(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Obj div(Obj other) {
|
||||
return toLst().div(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Obj pow(Obj other) {
|
||||
return toLst().pow(other);
|
||||
}
|
||||
|
||||
private Lst toLst() {
|
||||
Lst result = Lst.empty();
|
||||
Iterator<Obj> it = iterator();
|
||||
while (it.hasNext())
|
||||
result.append(it.next());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static class RangeIterator implements Iterator<Obj> {
|
||||
private Num current;
|
||||
private final Num to;
|
||||
private final Num by;
|
||||
|
||||
public RangeIterator(Num from, Num to, Num by) {
|
||||
this.current = from;
|
||||
this.to = to;
|
||||
this.by = by;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return by.doubleValue() > 0
|
||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Objects;
|
|||
|
||||
import static com.vectron.fcl.Fcl.STRICT;
|
||||
|
||||
public class Str implements Obj, ArithmeticOperand {
|
||||
public class Str implements Obj, ArithmeticOperand, Iterable<Chr> {
|
||||
private final String value;
|
||||
|
||||
public Str(String value) {
|
||||
|
@ -113,8 +113,9 @@ public class Str implements Obj, ArithmeticOperand {
|
|||
return Bool.TRUE;
|
||||
}
|
||||
|
||||
public Iterator<Str> iterator() {
|
||||
return new Iterator<Str>() {
|
||||
@Override
|
||||
public Iterator<Chr> iterator() {
|
||||
return new Iterator<Chr>() {
|
||||
private int index = 0;
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
|
@ -122,7 +123,7 @@ public class Str implements Obj, ArithmeticOperand {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Str next() {
|
||||
public Chr next() {
|
||||
return new Chr(value.charAt(index++));
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1069,6 +1069,49 @@ public class FclTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeArithmetic() {
|
||||
assertEquals("[ 1 2 3 ]", evalPop("1 3 .. round").toString());
|
||||
assertEquals("[ 16 16 17 17 17 ]", evalPop("256 300 10 ... sqrt round").toString());
|
||||
|
||||
assertEquals("[ 11 12 13 ]", evalPop("10 1 3 .. +").toString());
|
||||
assertEquals("[ 9 8 7 ]", evalPop("10 1 3 .. -").toString());
|
||||
assertEquals("[ 10 20 30 ]", evalPop("10 1 3 .. *").toString());
|
||||
assertEquals("[ 6.0 3.0 2.0 ]", evalPop("6 1 3 .. /").toString());
|
||||
|
||||
assertEquals("[ 11 12 13 ]", evalPop("1 3 .. 10 +").toString());
|
||||
assertEquals("[ -9 -8 -7 ]", evalPop("1 3 .. 10 -").toString());
|
||||
assertEquals("[ 10 20 30 ]", evalPop("1 3 .. 10 *").toString());
|
||||
assertEquals("[ 0.5 1.0 1.5 ]", evalPop("1 3 .. 2 /").toString());
|
||||
|
||||
assertEquals("[ 1.0 4.0 9.0 ]", evalPop("1 3 .. 2 pow").toString());
|
||||
assertEquals("[ 2.0 4.0 8.0 ]", evalPop("2 1 3 .. pow").toString());
|
||||
|
||||
assertEquals("[ 11 13 15 ]", evalPop("[ 10 11 12 ] 1 3 .. +").toString());
|
||||
assertEquals("[ 9 7 5 ]", evalPop("[ 10 9 8 ] 1 3 .. -").toString());
|
||||
assertEquals("[ 10 22 36 ]", evalPop("[ 10 11 12 ] 1 3 .. *").toString());
|
||||
assertEquals("[ 10.0 6.0 10.0 ]", evalPop("[ 10 12 30 ] 1 3 .. /").toString());
|
||||
assertEquals("[ 2.0 9.0 64.0 ]", evalPop("[ 2 3 4 ] 1 3 .. pow").toString());
|
||||
|
||||
assertEquals("[ 11 13 15 ]", evalPop("1 3 .. [ 10 11 12 ] +").toString());
|
||||
assertEquals("[ -9 1 -1 ]", evalPop("1 3 .. [ 10 1 4 ] -").toString());
|
||||
assertEquals("[ 2 6 12 ]", evalPop("1 3 .. [ 2 3 4 ] *").toString());
|
||||
assertEquals("[ 0.5 0.25 1.0 ]", evalPop("1 3 .. [ 2 8 3 ] /").toString());
|
||||
assertEquals("[ 1.0 8.0 27.0 ]", evalPop("1 3 .. [ 2 3 3 ] pow").toString());
|
||||
|
||||
assertEquals("[ 11 13 15 ]", evalPop("1 3 .. 10 12 .. +").toString());
|
||||
assertEquals("[ 9 8 7 ]", evalPop("10 12 .. 1 5 2 ... -").toString()); // [1 3 5]
|
||||
assertEquals("[ 10 22 36 ]", evalPop("1 3 .. 10 12 .. *").toString());
|
||||
assertEquals("[ 11.0 4.0 2.6 ]", evalPop("11 13 .. 1 5 2 ... /").toString()); // [1 3 5]
|
||||
assertEquals("[ 1.0 8.0 243.0 ]", evalPop("1 3 .. 1 5 2 ... pow").toString()); // [1 3 5]
|
||||
|
||||
assertEquals("[ 2 4 3 ]", evalPop("1 3 .. 1 2 .. +").toString());
|
||||
assertEquals("[ 9 8 12 ]", evalPop("10 12 .. 1 3 2 ... -").toString()); // [1 3]
|
||||
assertEquals("[ 10 22 3 ]", evalPop("1 3 .. 10 11 .. *").toString());
|
||||
assertEquals("[ 11.0 4.0 13.0 ]", evalPop("11 13 .. 1 3 2 ... /").toString()); // [1 3]
|
||||
assertEquals("[ 1.0 8.0 3.0 ]", evalPop("1 3 .. 1 3 2 ... pow").toString()); // [1 3]
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStrArithmetic() throws Exception {
|
||||
assertEquals("'ababab'", evalPop("3 'ab' *").toString());
|
||||
|
|
44
src/test/java/com/vectron/fcl/JsonSerializerTest.java
Normal file
44
src/test/java/com/vectron/fcl/JsonSerializerTest.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package com.vectron.fcl;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.vectron.fcl.types.Lst;
|
||||
import com.vectron.fcl.types.Num;
|
||||
import com.vectron.fcl.types.Obj;
|
||||
import com.vectron.fcl.types.Range;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class JsonSerializerTest {
|
||||
static FclTypeAdapter typeAdapter = new FclTypeAdapter();
|
||||
static Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Obj.class, typeAdapter)
|
||||
.setLenient()
|
||||
.serializeSpecialFloatingPointValues()
|
||||
.create();
|
||||
|
||||
static {
|
||||
typeAdapter.setGSon(gson);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeList() {
|
||||
Lst lst = Lst.empty();
|
||||
lst.append(new Num(1));
|
||||
lst.append(new Num(2));
|
||||
assertEquals(
|
||||
"{\"value\":[{\"value\":1,\"__type\":\"num\"},{\"value\":2,\"__type\":\"num\"}],\"__type\":\"lst\"}",
|
||||
gson.toJsonTree(lst, Obj.class).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerializeRange() {
|
||||
Range rng = Range.create(new Num(1), new Num(3), new Num(1));
|
||||
assertEquals(
|
||||
"{\"from\":{\"value\":1\"__type\":\"num\"},\"to\":{\"value\":3\"__type\":\"num\"},\"by\":{\"value\":1\"__type\":\"num\"},\"__type\":\"rng\"}",
|
||||
gson.toJsonTree(rng, Obj.class).toString());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue