mirror of
https://github.com/zeroflag/fcl.git
synced 2025-01-11 20:01:10 +01:00
- improved array arithmetic.
- fixed pstack overflow bug : tst false if 0 -> x then ;
This commit is contained in:
parent
3bc5060985
commit
ea2560dce3
22 changed files with 298 additions and 69 deletions
|
@ -153,6 +153,11 @@ public class Fcl {
|
||||||
? name.compareTo(((ColonDef) other).name)
|
? name.compareTo(((ColonDef) other).name)
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Var implements Word {
|
public class Var implements Word {
|
||||||
|
@ -253,6 +258,11 @@ public class Fcl {
|
||||||
? name.compareTo(((Var) other).name)
|
? name.compareTo(((Var) other).name)
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Val implements Word {
|
public class Val implements Word {
|
||||||
|
@ -352,6 +362,11 @@ public class Fcl {
|
||||||
? name.compareTo(((Val) other).name)
|
? name.compareTo(((Val) other).name)
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fcl(FclStack stack, int heapSize, Transcript transcript) {
|
public Fcl(FclStack stack, int heapSize, Transcript transcript) {
|
||||||
|
@ -381,9 +396,9 @@ public class Fcl {
|
||||||
stack.push(a.intDiv(b));
|
stack.push(a.intDiv(b));
|
||||||
});
|
});
|
||||||
addPrimitive("pow", () -> {
|
addPrimitive("pow", () -> {
|
||||||
Num exponent = stack.pop().asNum();
|
Obj exponent = stack.pop();
|
||||||
Num base = stack.pop().asNum();
|
Obj base = stack.pop();
|
||||||
stack.push(base.power(exponent));
|
stack.push(aOp(base).pow(exponent));
|
||||||
});
|
});
|
||||||
addPrimitive("and", () -> stack.push(lOp(stack.pop()).and(stack.pop())));
|
addPrimitive("and", () -> stack.push(lOp(stack.pop()).and(stack.pop())));
|
||||||
addPrimitive("or", () -> stack.push((lOp(stack.pop())).or(stack.pop())));
|
addPrimitive("or", () -> stack.push((lOp(stack.pop())).or(stack.pop())));
|
||||||
|
@ -484,7 +499,7 @@ public class Fcl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArithmeticOperand aOp(Obj obj) {
|
public static ArithmeticOperand aOp(Obj obj) {
|
||||||
try {
|
try {
|
||||||
return (ArithmeticOperand) obj;
|
return (ArithmeticOperand) obj;
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
|
@ -557,6 +572,10 @@ public class Fcl {
|
||||||
* Like: if else then, loops, quotations
|
* Like: if else then, loops, quotations
|
||||||
*/
|
*/
|
||||||
public void compileTmpAndEval(String script) {
|
public void compileTmpAndEval(String script) {
|
||||||
|
// XXX ; make locals work, ; drops the frame, so we need to alloc first, normally this is done by the overridden colon
|
||||||
|
Word frameAlloc = dict.at("frame.alloc");
|
||||||
|
if (frameAlloc != null)
|
||||||
|
frameAlloc.enter();
|
||||||
int savedDp = dp;
|
int savedDp = dp;
|
||||||
Mode savedMode = mode;
|
Mode savedMode = mode;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -6,8 +6,8 @@ import com.google.gson.JsonObject;
|
||||||
import com.google.gson.TypeAdapter;
|
import com.google.gson.TypeAdapter;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
import com.vectron.fcl.Fcl;
|
|
||||||
import com.vectron.fcl.types.Bool;
|
import com.vectron.fcl.types.Bool;
|
||||||
|
import com.vectron.fcl.types.Chr;
|
||||||
import com.vectron.fcl.types.Dic;
|
import com.vectron.fcl.types.Dic;
|
||||||
import com.vectron.fcl.types.JvmObj;
|
import com.vectron.fcl.types.JvmObj;
|
||||||
import com.vectron.fcl.types.Lst;
|
import com.vectron.fcl.types.Lst;
|
||||||
|
@ -32,6 +32,7 @@ public class FclTypeAdapter extends TypeAdapter<Object> {
|
||||||
register("num", Num.class);
|
register("num", Num.class);
|
||||||
register("bool", Bool.class);
|
register("bool", Bool.class);
|
||||||
register("str", Str.class);
|
register("str", Str.class);
|
||||||
|
register("chr", Chr.class);
|
||||||
register("dic", Dic.class);
|
register("dic", Dic.class);
|
||||||
register("sym", Symbol.class);
|
register("sym", Symbol.class);
|
||||||
register("lst", Lst.class);
|
register("lst", Lst.class);
|
||||||
|
|
|
@ -5,4 +5,5 @@ public interface ArithmeticOperand {
|
||||||
Obj sub(Obj other);
|
Obj sub(Obj other);
|
||||||
Obj mul(Obj other);
|
Obj mul(Obj other);
|
||||||
Obj div(Obj other);
|
Obj div(Obj other);
|
||||||
|
Obj pow(Obj other);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,11 @@ public class Bool implements Obj, LogicOperand {
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long longValue() {
|
public long longValue() {
|
||||||
if (STRICT) throw new TypeMismatched(this, "long");
|
if (STRICT) throw new TypeMismatched(this, "long");
|
||||||
|
|
13
src/main/java/com/vectron/fcl/types/Chr.java
Normal file
13
src/main/java/com/vectron/fcl/types/Chr.java
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package com.vectron.fcl.types;
|
||||||
|
|
||||||
|
public class Chr extends Str {
|
||||||
|
|
||||||
|
public Chr(Character chr) {
|
||||||
|
super(String.valueOf(chr));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,6 +65,11 @@ public class Dic implements Obj {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<Lst> iterator() {
|
public Iterator<Lst> iterator() {
|
||||||
return new Iterator<Lst>() {
|
return new Iterator<Lst>() {
|
||||||
private Iterator<Map.Entry<Obj,Obj>> it = value.entrySet().iterator();
|
private Iterator<Map.Entry<Obj,Obj>> it = value.entrySet().iterator();
|
||||||
|
|
|
@ -89,6 +89,11 @@ public class JvmObj implements Obj {
|
||||||
return value();
|
return value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Obj o) {
|
public int compareTo(Obj o) {
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.vectron.fcl.types;
|
package com.vectron.fcl.types;
|
||||||
|
|
||||||
|
import com.vectron.fcl.Fcl;
|
||||||
import com.vectron.fcl.exceptions.TypeMismatched;
|
import com.vectron.fcl.exceptions.TypeMismatched;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -75,6 +76,10 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
return value.get(index.intValue());
|
return value.get(index.intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Obj atIfAbsent(int index, Obj defaultValue) {
|
||||||
|
return index < size() ? value.get(index) : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
public int indexOf(Obj item) {
|
public int indexOf(Obj item) {
|
||||||
return value.indexOf(item);
|
return value.indexOf(item);
|
||||||
}
|
}
|
||||||
|
@ -104,6 +109,11 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
value.clear();
|
value.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<Obj> iterator() {
|
public Iterator<Obj> iterator() {
|
||||||
return value.iterator();
|
return value.iterator();
|
||||||
}
|
}
|
||||||
|
@ -115,6 +125,23 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Lst flatten() {
|
||||||
|
Lst result = Lst.empty();
|
||||||
|
result.value.addAll(flatten(this));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Obj> flatten(Lst nested) {
|
||||||
|
List<Obj> result = new ArrayList<>();
|
||||||
|
for (Obj each : nested.value) {
|
||||||
|
if (each instanceof Lst)
|
||||||
|
result.addAll(flatten((Lst)each));
|
||||||
|
else
|
||||||
|
result.add(each);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Str asStr() {
|
public Str asStr() {
|
||||||
return new Str(toString());
|
return new Str(toString());
|
||||||
|
@ -137,7 +164,15 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
if (other instanceof Num) {
|
if (other instanceof Num) {
|
||||||
Lst result = Lst.empty();
|
Lst result = Lst.empty();
|
||||||
for (Obj each : value)
|
for (Obj each : value)
|
||||||
result.append(each.asNum().add(other));
|
result.append(Fcl.aOp(each).add(other));
|
||||||
|
return result;
|
||||||
|
} else if (other instanceof Lst) {
|
||||||
|
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);
|
||||||
|
result.append(Fcl.aOp(a).add(b));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeMismatched("+", this, other);
|
throw new TypeMismatched("+", this, other);
|
||||||
|
@ -149,7 +184,15 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
if (other instanceof Num) {
|
if (other instanceof Num) {
|
||||||
Lst result = Lst.empty();
|
Lst result = Lst.empty();
|
||||||
for (Obj each : value)
|
for (Obj each : value)
|
||||||
result.append(each.asNum().sub(other));
|
result.append(Fcl.aOp(each).sub(other));
|
||||||
|
return result;
|
||||||
|
} else if (other instanceof Lst) {
|
||||||
|
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);
|
||||||
|
result.append(Fcl.aOp(a).sub(b));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeMismatched("-", this, other);
|
throw new TypeMismatched("-", this, other);
|
||||||
|
@ -161,7 +204,15 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
if (other instanceof Num) {
|
if (other instanceof Num) {
|
||||||
Lst result = Lst.empty();
|
Lst result = Lst.empty();
|
||||||
for (Obj each : value)
|
for (Obj each : value)
|
||||||
result.append(each.asNum().mul(other));
|
result.append(Fcl.aOp(each).mul(other));
|
||||||
|
return result;
|
||||||
|
} else if (other instanceof Lst) {
|
||||||
|
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);
|
||||||
|
result.append(Fcl.aOp(a).mul(b));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeMismatched("*", this, other);
|
throw new TypeMismatched("*", this, other);
|
||||||
|
@ -173,10 +224,38 @@ public class Lst implements Obj, ArithmeticOperand {
|
||||||
if (other instanceof Num) {
|
if (other instanceof Num) {
|
||||||
Lst result = Lst.empty();
|
Lst result = Lst.empty();
|
||||||
for (Obj each : value)
|
for (Obj each : value)
|
||||||
result.append(each.asNum().div(other));
|
result.append(Fcl.aOp(each).div(other));
|
||||||
|
return result;
|
||||||
|
} else if (other instanceof Lst) {
|
||||||
|
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));
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TypeMismatched("/", this, other);
|
throw new TypeMismatched("/", this, other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Obj pow(Obj other) {
|
||||||
|
if (other instanceof Num) {
|
||||||
|
Lst result = Lst.empty();
|
||||||
|
for (Obj each : value)
|
||||||
|
result.append(Fcl.aOp(each).pow(other));
|
||||||
|
return result;
|
||||||
|
} else if (other instanceof Lst) {
|
||||||
|
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);
|
||||||
|
result.append(Fcl.aOp(a).pow(b));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
throw new TypeMismatched("pow", this, other);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,4 +63,9 @@ public class Nil implements Obj {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "nil";
|
return "nil";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import static com.vectron.fcl.Fcl.STRICT;
|
||||||
public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
||||||
public static final Num ZERO = new Num(0);
|
public static final Num ZERO = new Num(0);
|
||||||
public static final Num ONE = new Num(1);
|
public static final Num ONE = new Num(1);
|
||||||
|
public static final Num MINUS_ONE = new Num(-1);
|
||||||
public static final Num NAN = new Num(Double.NaN);
|
public static final Num NAN = new Num(Double.NaN);
|
||||||
private static final DecimalFormat format;
|
private static final DecimalFormat format;
|
||||||
private final Number value;
|
private final Number value;
|
||||||
|
@ -92,6 +93,8 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
||||||
return new Num((Double) value - (Long)other.value());
|
return new Num((Double) value - (Long)other.value());
|
||||||
else if (value instanceof Double && other.value() instanceof Double)
|
else if (value instanceof Double && other.value() instanceof Double)
|
||||||
return new Num((Double) value - (Double) other.value());
|
return new Num((Double) value - (Double) other.value());
|
||||||
|
else if (other instanceof Lst)
|
||||||
|
return ((Lst) other).mul(Num.MINUS_ONE).add(this);
|
||||||
else if (STRICT)
|
else if (STRICT)
|
||||||
throw new TypeMismatched("-", this, other);
|
throw new TypeMismatched("-", this, other);
|
||||||
return Num.NAN;
|
return Num.NAN;
|
||||||
|
@ -126,22 +129,25 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
||||||
return new Num((Double) value / (Long)other.value());
|
return new Num((Double) value / (Long)other.value());
|
||||||
else if (value instanceof Double && other.value() instanceof Double)
|
else if (value instanceof Double && other.value() instanceof Double)
|
||||||
return new Num((Double) value / (Double) other.value());
|
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 (STRICT)
|
else if (STRICT)
|
||||||
throw new TypeMismatched("/", this, other);
|
throw new TypeMismatched("/", this, other);
|
||||||
return Num.NAN;
|
return Num.NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Num power(Num exponent) {
|
@Override
|
||||||
if (value instanceof Long && exponent.value instanceof Long)
|
public Obj pow(Obj other) {
|
||||||
return new Num(Math.pow(((Long) value).doubleValue(), ((Long) exponent.value).doubleValue()));
|
if (other instanceof Num) {
|
||||||
else if (value instanceof Long && exponent.value instanceof Double)
|
return new Num(Math.pow(doubleValue(), other.doubleValue()));
|
||||||
return new Num(Math.pow(((Long) value).doubleValue(), exponent.doubleValue()));
|
} else if (other instanceof Lst) {
|
||||||
else if (value instanceof Double && exponent.value instanceof Long)
|
Lst result = Lst.empty();
|
||||||
return new Num(Math.pow((Double)value, ((Long) exponent.value).doubleValue()));
|
for (Obj each : ((Lst) other).value())
|
||||||
else if (value instanceof Double && exponent.value instanceof Double)
|
result.append(this.pow(each));
|
||||||
return new Num(Math.pow((Double)value, exponent.doubleValue()));
|
return result;
|
||||||
else if (STRICT)
|
} else if (STRICT) {
|
||||||
throw new TypeMismatched("POW", this, exponent);
|
throw new TypeMismatched("pow", this, other);
|
||||||
|
}
|
||||||
return Num.NAN;
|
return Num.NAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,4 +292,9 @@ public class Num implements Obj, LogicOperand, ArithmeticOperand {
|
||||||
return !((Double) value).isNaN() && !((Double) value).isInfinite();
|
return !((Double) value).isNaN() && !((Double) value).isInfinite();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,5 @@ public interface Obj extends Comparable<Obj> {
|
||||||
Str asStr();
|
Str asStr();
|
||||||
Object value();
|
Object value();
|
||||||
Object unwrap();
|
Object unwrap();
|
||||||
|
Bool iterable();
|
||||||
}
|
}
|
|
@ -104,4 +104,9 @@ public class Primitive implements Word {
|
||||||
? name.compareTo(((Primitive) other).name)
|
? name.compareTo(((Primitive) other).name)
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,4 +75,9 @@ public class Quot implements Obj {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Quotation: " + address + ", " + stackFrame;
|
return "Quotation: " + address + ", " + stackFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,11 @@ public class Range implements Obj {
|
||||||
return new Str(toString());
|
return new Str(toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<Obj> iterator() {
|
public Iterator<Obj> iterator() {
|
||||||
if (iterator == null)
|
if (iterator == null)
|
||||||
iterator = new RangeIterator();
|
iterator = new RangeIterator();
|
||||||
|
|
|
@ -108,6 +108,11 @@ public class Str implements Obj, ArithmeticOperand {
|
||||||
return new Str(new StringBuilder(value).reverse().toString());
|
return new Str(new StringBuilder(value).reverse().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public Iterator<Str> iterator() {
|
public Iterator<Str> iterator() {
|
||||||
return new Iterator<Str>() {
|
return new Iterator<Str>() {
|
||||||
private int index = 0;
|
private int index = 0;
|
||||||
|
@ -118,7 +123,7 @@ public class Str implements Obj, ArithmeticOperand {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Str next() {
|
public Str next() {
|
||||||
return new Str(Character.toString(value.charAt(index++)));
|
return new Chr(value.charAt(index++));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -151,6 +156,8 @@ public class Str implements Obj, ArithmeticOperand {
|
||||||
return new Str(String.format(value, a));
|
return new Str(String.format(value, a));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Str flatten() { return this; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Obj add(Obj other) {
|
public Obj add(Obj other) {
|
||||||
throw new TypeMismatched("+", this, other);
|
throw new TypeMismatched("+", this, other);
|
||||||
|
@ -177,4 +184,9 @@ public class Str implements Obj, ArithmeticOperand {
|
||||||
public Obj div(Obj other) {
|
public Obj div(Obj other) {
|
||||||
throw new TypeMismatched("+", this, other);
|
throw new TypeMismatched("+", this, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Obj pow(Obj other) {
|
||||||
|
throw new TypeMismatched("pow", this, other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,4 +60,9 @@ public class Symbol implements Obj {
|
||||||
? symbol.compareTo(((Symbol) other).symbol)
|
? symbol.compareTo(((Symbol) other).symbol)
|
||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bool iterable() {
|
||||||
|
return Bool.FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
: jvmValue ( p -- o ) :value jvm-call-method ;
|
: jvmValue ( p -- o ) :value jvm-call-method ;
|
||||||
: reverse ( l -- l ) :reverse jvm-call-method ;
|
: reverse ( l -- l ) :reverse jvm-call-method ;
|
||||||
: format ( l s -- s ) :format/t jvm-call-method ;
|
: format ( l s -- s ) :format/t jvm-call-method ;
|
||||||
|
: iterator? ( o -- b ) :iterable jvm-call-method ;
|
||||||
|
: flatten ( l -- l ) dup :flatten jvm-has-method if :flatten jvm-call-method then ;
|
||||||
|
|
||||||
: each ( c q -- )
|
: each ( c q -- )
|
||||||
-> q iter -> it
|
-> q iter -> it
|
||||||
|
@ -55,7 +57,7 @@
|
||||||
loop
|
loop
|
||||||
result ;
|
result ;
|
||||||
|
|
||||||
: peel ( l -- .. ) -> lst lst { } each ;
|
: peel ( l -- .. ) -> lst lst iterator? if lst { } each else lst then ;
|
||||||
: peel# ( m -- .. ) -> m m { dup 1st swap 2nd } each ;
|
: peel# ( m -- .. ) -> m m { dup 1st swap 2nd } each ;
|
||||||
|
|
||||||
: >list* ( .. -- l )
|
: >list* ( .. -- l )
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
var: #loc ( number of local variables per word, used in compile time )
|
var: #loc ( number of local variables per word, used in compile time )
|
||||||
var: psp ( top of the parameter stack, each allocation adds max#loc to this )
|
var: psp ( top of the parameter stack, each allocation adds max#loc to this )
|
||||||
var: qpsp ( parameter stack pointer used by quotations )
|
var: qpsp ( parameter stack pointer used by quotations )
|
||||||
var: frame.allocated ( compile time variable for checking if a frame was already allocated )
|
|
||||||
var: q.count ( compile time counter for quotations, nested into each other )
|
var: q.count ( compile time counter for quotations, nested into each other )
|
||||||
var: ldp
|
var: ldp
|
||||||
|
|
||||||
|
@ -29,7 +28,6 @@ max#loc look-word-size *
|
||||||
allot val: scratch ( scratch area for compiling temporary lookup words )
|
allot val: scratch ( scratch area for compiling temporary lookup words )
|
||||||
|
|
||||||
0 q.count !
|
0 q.count !
|
||||||
false frame.allocated !
|
|
||||||
|
|
||||||
: full.check ( -- ) psp @ ps.size >= if 'pstack overflow' abort then ;
|
: full.check ( -- ) psp @ ps.size >= if 'pstack overflow' abort then ;
|
||||||
: empty.check ( -- ) psp @ 0 <= if 'pstack underflow' abort then ;
|
: empty.check ( -- ) psp @ 0 <= if 'pstack underflow' abort then ;
|
||||||
|
@ -70,11 +68,7 @@ false frame.allocated !
|
||||||
|
|
||||||
: local ( n -- )
|
: local ( n -- )
|
||||||
check#
|
check#
|
||||||
frame.allocated @ not if ( is this the first local? )
|
#loc @ 0 = if scratch ldp ! then
|
||||||
true frame.allocated !
|
|
||||||
['] frame.alloc , ( alloc new stack frame for max#loc )
|
|
||||||
scratch ldp !
|
|
||||||
then
|
|
||||||
(frame.top)
|
(frame.top)
|
||||||
['] lit , #loc @ , ( local index )
|
['] lit , #loc @ , ( local index )
|
||||||
['] - , ['] ! , ( move local to from data stack to the stack frame )
|
['] - , ['] ! , ( move local to from data stack to the stack frame )
|
||||||
|
@ -94,13 +88,12 @@ false frame.allocated !
|
||||||
: -> immediate 1 local ;
|
: -> immediate 1 local ;
|
||||||
: => immediate 0 local ;
|
: => immediate 0 local ;
|
||||||
|
|
||||||
: unwind frame.allocated @ if ['] frame.drop , then ;
|
: exit immediate ['] frame.drop , exit.prim @ , ;
|
||||||
|
: old; immediate exit.prim @ , nil , interpret reveal ;
|
||||||
: exit immediate unwind exit.prim @ , ;
|
|
||||||
|
|
||||||
: ; immediate override
|
: ; immediate override
|
||||||
( runtime )
|
( runtime )
|
||||||
unwind
|
['] frame.drop ,
|
||||||
exit.prim @ ,
|
exit.prim @ ,
|
||||||
nil ,
|
nil ,
|
||||||
( compile time )
|
( compile time )
|
||||||
|
@ -109,6 +102,7 @@ false frame.allocated !
|
||||||
jvm-null names i + !
|
jvm-null names i + !
|
||||||
loop
|
loop
|
||||||
0 #loc !
|
0 #loc !
|
||||||
false frame.allocated !
|
|
||||||
interpret
|
interpret
|
||||||
reveal ;
|
reveal ;
|
||||||
|
|
||||||
|
: : override : ['] frame.alloc , old;
|
|
@ -1,5 +1,5 @@
|
||||||
: hist ( c -- m )
|
: hist ( c -- m )
|
||||||
dup 'iterator' jvm-has-method not if
|
dup iterator? not if
|
||||||
drop #[ ]# exit
|
drop #[ ]# exit
|
||||||
then
|
then
|
||||||
<map> -> tbl {
|
<map> -> tbl {
|
||||||
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
: match: immediate ` lastword set-predicate ;
|
: match: immediate ` lastword set-predicate ;
|
||||||
|
|
||||||
: round* { round } map* ;
|
|
||||||
|
|
||||||
: npv ( cashflow rate -- n )
|
: npv ( cashflow rate -- n )
|
||||||
-> rate 0 => year
|
-> rate 0 => year
|
||||||
{ rate year @ dis year inc } map sum ;
|
{ rate year @ dis year inc } map sum ;
|
||||||
|
@ -61,3 +59,7 @@ var: juggler.steps 5 juggler.steps !
|
||||||
: udp-send-byte ( host port byte -- n ) :com.vectron.forthcalc.support.Udp/sendByte/Nis jvm-call-static ;
|
: udp-send-byte ( host port byte -- n ) :com.vectron.forthcalc.support.Udp/sendByte/Nis jvm-call-static ;
|
||||||
: udp-send-str ( host port str -- n ) :com.vectron.forthcalc.support.Udp/sendStr/sis jvm-call-static ;
|
: udp-send-str ( host port str -- n ) :com.vectron.forthcalc.support.Udp/sendStr/sis jvm-call-static ;
|
||||||
: udp-send-lst ( host port lst -- n ) :com.vectron.forthcalc.support.Udp/sendLst/Tis jvm-call-static ;
|
: udp-send-lst ( host port lst -- n ) :com.vectron.forthcalc.support.Udp/sendLst/Tis jvm-call-static ;
|
||||||
|
|
||||||
|
: round ( n -- n ) dup iterator? if { round } map else round1 then ;
|
||||||
|
: sqrt ( n -- n ) dup iterator? if { sqrt } map else sqrt1 then ;
|
||||||
|
: round* { round } map* ;
|
|
@ -40,8 +40,8 @@
|
||||||
: tanh ( n -- n ) :java.lang.Math/tanh/d jvm-call-static ;
|
: tanh ( n -- n ) :java.lang.Math/tanh/d jvm-call-static ;
|
||||||
( math )
|
( math )
|
||||||
: e ( n -- n ) :java.lang.Math/E jvm-static-var ;
|
: e ( n -- n ) :java.lang.Math/E jvm-static-var ;
|
||||||
: round ( n -- n ) :java.lang.Math/round/d jvm-call-static ;
|
: round1 ( n -- n ) :java.lang.Math/round/d jvm-call-static ;
|
||||||
: sqrt ( n -- n ) :java.lang.Math/sqrt/d jvm-call-static ;
|
: sqrt1 ( n -- n ) :java.lang.Math/sqrt/d jvm-call-static ;
|
||||||
: 10log ( n -- n ) :java.lang.Math/log10/d jvm-call-static ;
|
: 10log ( n -- n ) :java.lang.Math/log10/d jvm-call-static ;
|
||||||
: nlog ( n n -- n ) swap 10log swap 10log / ;
|
: nlog ( n n -- n ) swap 10log swap 10log / ;
|
||||||
: 2log ( n -- n ) 2.0 nlog ;
|
: 2log ( n -- n ) 2.0 nlog ;
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
dup 1 <= if
|
dup 1 <= if
|
||||||
drop 1
|
drop 1
|
||||||
else
|
else
|
||||||
round dup 1 do i * loop
|
round1 dup 1 do i * loop
|
||||||
then ;
|
then ;
|
||||||
: avg* ( .. -- n ) depth dup 1 < if drop else >r sum* r> / then ;
|
: avg* ( .. -- n ) depth dup 1 < if drop else >r sum* r> / then ;
|
||||||
: rnd ( -- n ) :com.vectron.fcl.interop.JvmInterOp/random jvm-call-static ;
|
: rnd ( -- n ) :com.vectron.fcl.interop.JvmInterOp/random jvm-call-static ;
|
||||||
|
|
|
@ -11,10 +11,6 @@
|
||||||
|
|
||||||
: { immediate
|
: { immediate
|
||||||
q.count inc
|
q.count inc
|
||||||
frame.allocated @ not if ( We need to have a PSP up front for <q>, because quotations might have its own locals )
|
|
||||||
['] frame.alloc , ( But at this point it might not be available yet unless the enclosing function has locals before the quotations )
|
|
||||||
true frame.allocated !
|
|
||||||
then
|
|
||||||
['] lit , here 6 + , ( beginning of the quotation )
|
['] lit , here 6 + , ( beginning of the quotation )
|
||||||
(psp)
|
(psp)
|
||||||
['] <q> , ( make a quotation object from address + psp )
|
['] <q> , ( make a quotation object from address + psp )
|
||||||
|
|
|
@ -819,6 +819,18 @@ public class FclTest {
|
||||||
assertEquals(0, evalPop("m clear m size").intValue());
|
assertEquals(0, evalPop("m clear m size").intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMaps2() throws Exception {
|
||||||
|
assertEquals("[ [ 1 3 ] ]", evalPop("#[ 0.8 3.3 ]# round").toString());
|
||||||
|
assertEquals("[ [ 1.0 3.0 ] ]", evalPop("#[ 1 9 ]# sqrt").toString());
|
||||||
|
try {
|
||||||
|
evalPop("#[ 'a' 1 ]# round");
|
||||||
|
fail("expected type mismatch");
|
||||||
|
} catch (TypeMismatched expected) {
|
||||||
|
resetForth();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testList() {
|
public void testList() {
|
||||||
assertEquals(0, evalPop("<list> size").intValue());
|
assertEquals(0, evalPop("<list> size").intValue());
|
||||||
|
@ -994,23 +1006,38 @@ public class FclTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListArithmetic() {
|
public void testListArithmetic() throws Exception {
|
||||||
try {
|
assertEquals("[ 5 7 9 ]", evalPop("[ 1 2 3 ] [ 4 5 6 ] +").toString());
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] [ 1 2 3 ] +").toString());
|
assertEquals("[ -3 1 0 ]", evalPop("[ 1 2 3 ] [ 4 1 3 ] -").toString());
|
||||||
fail();
|
assertEquals("[ 4 10 18 ]", evalPop("[ 1 2 3 ] [ 4 5 6 ] *").toString());
|
||||||
} catch (TypeMismatched e) { }
|
assertEquals("[ 4.0 2.5 2.0 ]", evalPop("[ 4 5 6 ] [ 1 2 3 ] /").toString());
|
||||||
try {
|
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] [ 1 2 3 ] -").toString());
|
assertEquals("[ 5 7 3 ]", evalPop("[ 1 2 3 ] [ 4 5 ] +").toString());
|
||||||
fail();
|
assertEquals("[ -3 1 3 ]", evalPop("[ 1 2 3 ] [ 4 1 ] -").toString());
|
||||||
} catch (TypeMismatched e) { }
|
assertEquals("[ 4 10 3 ]", evalPop("[ 1 2 3 ] [ 4 5 ] *").toString());
|
||||||
try {
|
assertEquals("[ 4.0 2.5 6.0 ]", evalPop("[ 4 5 6 ] [ 1 2 ] /").toString());
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] [ 1 2 3 ] *").toString());
|
|
||||||
fail();
|
assertEquals("[ 5 7 6 ]", evalPop("[ 1 2 ] [ 4 5 6 ] +").toString());
|
||||||
} catch (TypeMismatched e) { }
|
assertEquals("[ -3 1 -3 ]", evalPop("[ 1 2 ] [ 4 1 3 ] -").toString());
|
||||||
try {
|
assertEquals("[ 4 10 6 ]", evalPop("[ 1 2 ] [ 4 5 6 ] *").toString());
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] [ 1 2 3 ] /").toString());
|
assertEquals("[ 4.0 2.5 0.0 ]", evalPop("[ 4 5 ] [ 1 2 3 ] /").toString());
|
||||||
fail();
|
|
||||||
} catch (TypeMismatched e) { }
|
assertEquals("[ 5 7 [ 11 5 ] ]", evalPop("[ 4 5 [ 7 ] ] [ 1 2 [ 4 5 ] ] +").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 4 5 [ 6 7 ] ]", evalPop("[ 1 2 [ 3 4 ] ] 3 +").toString());
|
||||||
|
assertEquals("[ 0 2 [ 5 3 ] ]", evalPop("[ 2 4 [ 7 5 ] ] 2 -").toString());
|
||||||
|
assertEquals("[ 3 6 [ 9 12 ] ]", evalPop("[ 1 2 [ 3 4 ] ] 3 *").toString());
|
||||||
|
assertEquals("[ 1.0 2.0 [ 3.0 4.0 ] ]", evalPop("[ 2 4 [ 6 8 ] ] 2 /").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 2.0 4.0 3.0 ]", evalPop("[ 4 16 9 ] sqrt").toString());
|
||||||
|
assertEquals("[ 1 6 3 ]", evalPop("[ 1.3 5.6 3.2 ] round").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 2.0 4.0 [ 3.0 ] ]", evalPop("[ 4 16 [ 9 ] ] sqrt").toString());
|
||||||
|
assertEquals("[ 1 [ 6 ] 3 ]", evalPop("[ 1.3 [ 5.6 ] 3.2 ] round").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 1 2 3 ]", evalPop("[ 1 2 3 ] flatten").toString());
|
||||||
|
assertEquals("[ 1 2 3 ]", evalPop("[ 1 [ 2 ] 3 ] flatten").toString());
|
||||||
|
assertEquals("[ 4 16 9 10 3 3 1 ]", evalPop("[ 4 16 [ 9 [ 10 ] [ 3 ] ] [ 3 1 ] ] flatten").toString());
|
||||||
|
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("3 [ 1 2 3 ] *").toString());
|
assertEquals("[ 3 6 9 ]", evalPop("3 [ 1 2 3 ] *").toString());
|
||||||
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] 3 *").toString());
|
assertEquals("[ 3 6 9 ]", evalPop("[ 1 2 3 ] 3 *").toString());
|
||||||
|
@ -1018,20 +1045,46 @@ public class FclTest {
|
||||||
assertEquals("[ 4 5 6 ]", evalPop("3 [ 1 2 3 ] +").toString());
|
assertEquals("[ 4 5 6 ]", evalPop("3 [ 1 2 3 ] +").toString());
|
||||||
assertEquals("[ 4 5 6 ]", evalPop("[ 1 2 3 ] 3 +").toString());
|
assertEquals("[ 4 5 6 ]", evalPop("[ 1 2 3 ] 3 +").toString());
|
||||||
assertEquals("[ 1 2 3 ]", evalPop("[ 4 5 6 ] 3 -").toString());
|
assertEquals("[ 1 2 3 ]", evalPop("[ 4 5 6 ] 3 -").toString());
|
||||||
|
|
||||||
|
assertEquals("[ -1 -2 -3 ]", evalPop("3 [ 4 5 6 ] -").toString());
|
||||||
|
assertEquals("[ 2 1 0 ]", evalPop("3 [ 1 2 3 ] -").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 5.0 2.0 10.0 ]", evalPop("10 [ 2 5 1 ] /").toString());
|
||||||
|
|
||||||
|
assertEquals("[ 1.0 2.0 4.0 8.0 ]", evalPop("2 [ 0 1 2 3 ] pow").toString());
|
||||||
|
assertEquals("[ 1.0 4.0 9.0 ]", evalPop("[ 1 2 3 ] 2 pow").toString());
|
||||||
|
assertEquals("[ 25.0 27.0 16.0 ]", evalPop("[ 5 3 2 ] [ 2 3 4 ] pow").toString());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertEquals("[ 2 1 0 ]", evalPop("3 [ 1 2 3 ] -").toString());
|
evalPop("[ 'a' ] sqrt");
|
||||||
fail();
|
fail("expected type mismatch");
|
||||||
} catch (TypeMismatched e) { }
|
} catch (TypeMismatched expected) {
|
||||||
|
resetForth();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
assertEquals("[ 5 2 10 ]", evalPop("10 [ 2 5 1 ] /").toString());
|
evalPop("[ 'a' ] round");
|
||||||
fail();
|
fail("expected type mismatch");
|
||||||
} catch (TypeMismatched e) { }
|
} catch (TypeMismatched expected) {
|
||||||
|
resetForth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStrArithmetic() {
|
public void testStrArithmetic() throws Exception {
|
||||||
assertEquals("'ababab'", evalPop("3 'ab' *").toString());
|
assertEquals("'ababab'", evalPop("3 'ab' *").toString());
|
||||||
assertEquals("'ababab'", evalPop("'ab' 3 *").toString());
|
assertEquals("'ababab'", evalPop("'ab' 3 *").toString());
|
||||||
|
try {
|
||||||
|
evalPop("'ab' sqrt");
|
||||||
|
fail("expected type mismatch");
|
||||||
|
} catch (TypeMismatched expected) {
|
||||||
|
resetForth();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
evalPop("'ab' round");
|
||||||
|
fail("expected type mismatch");
|
||||||
|
} catch (TypeMismatched expected) {
|
||||||
|
resetForth();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1051,6 +1104,11 @@ public class FclTest {
|
||||||
@Test
|
@Test
|
||||||
public void testQuotations() {
|
public void testQuotations() {
|
||||||
assertEquals(2, evalPop(": tst 1 { 1+ } yield ; tst ").intValue());
|
assertEquals(2, evalPop(": tst 1 { 1+ } yield ; tst ").intValue());
|
||||||
|
assertEquals(2, evalPop(": tst 1 true if { 1+ } yield then ; tst ").intValue());
|
||||||
|
assertEquals(2, evalPop(": tst 1 true if { 1+ } yield else 1 0 / then ; tst ").intValue());
|
||||||
|
assertEquals(3, evalPop(": tst 1 false if { 0 / } yield else 2 + then ; tst ").intValue());
|
||||||
|
assertEquals(42, evalPop(": tst true if 42 -> x x else 43 then ; tst").intValue());
|
||||||
|
assertEquals(43, evalPop(": tst false if 42 -> x x else 43 then ; tst").intValue());
|
||||||
assertEquals(asList(101l, 100l), evalGetStack(": tst 100 { 1+ } keep ; tst"));
|
assertEquals(asList(101l, 100l), evalGetStack(": tst 100 { 1+ } keep ; tst"));
|
||||||
assertEquals(asList(11l, 100l), evalGetStack(": tst 10 100 { 1+ } dip ; tst"));
|
assertEquals(asList(11l, 100l), evalGetStack(": tst 10 100 { 1+ } dip ; tst"));
|
||||||
assertEquals(asList(11l, 9l), evalGetStack(": tst 10 { 1+ } { 1- } bi ; tst"));
|
assertEquals(asList(11l, 9l), evalGetStack(": tst 10 { 1+ } { 1- } bi ; tst"));
|
||||||
|
|
Loading…
Reference in a new issue