- improved array arithmetic.

- fixed pstack overflow bug : tst false if 0 -> x then ;
This commit is contained in:
zeroflag 2022-02-26 13:50:13 +01:00
parent 3bc5060985
commit ea2560dce3
22 changed files with 298 additions and 69 deletions

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,4 +9,5 @@ public interface Obj extends Comparable<Obj> {
Str asStr(); Str asStr();
Object value(); Object value();
Object unwrap(); Object unwrap();
Bool iterable();
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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