This commit is contained in:
zeroflag 2022-12-08 10:37:09 +01:00
parent bb5e19461b
commit 43b718d1a7
7 changed files with 190 additions and 55 deletions

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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++));
}
};

View file

@ -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());

View 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());
}
}