From 7fa71a71a99dd4e7c1ecb8553f0afacb3da3a180 Mon Sep 17 00:00:00 2001 From: zeroflag Date: Sun, 11 Jul 2021 18:56:55 +0200 Subject: [PATCH] predicate words experiment --- src/main/java/com/vectron/fcl/Dictionary.java | 6 +- src/main/java/com/vectron/fcl/Fcl.java | 66 ++++++++++++++----- .../java/com/vectron/fcl/types/Primitive.java | 15 +++-- src/main/java/com/vectron/fcl/types/Word.java | 5 +- src/main/res/raw/misc.forth | 7 +- src/main/res/raw/plot.forth | 3 +- src/test/java/com/vectron/fcl/FclTest.java | 10 +++ 7 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/vectron/fcl/Dictionary.java b/src/main/java/com/vectron/fcl/Dictionary.java index 9b0020a..d52e91c 100644 --- a/src/main/java/com/vectron/fcl/Dictionary.java +++ b/src/main/java/com/vectron/fcl/Dictionary.java @@ -9,8 +9,10 @@ import java.util.Set; public class Dictionary { private final List dict = new ArrayList<>(); + private final Fcl fcl; - public Dictionary() { + public Dictionary(Fcl fcl) { + this.fcl = fcl; } public void add(Word word) { @@ -20,7 +22,7 @@ public class Dictionary { public Word at(String name) { for (int i = dict.size() - 1; i >= 0; i--) { Word each = dict.get(i); - if (each.visible() && name.equals(each.name())) + if (each.match(name, fcl)) return each; } return null; diff --git a/src/main/java/com/vectron/fcl/Fcl.java b/src/main/java/com/vectron/fcl/Fcl.java index 2623c58..a9438da 100644 --- a/src/main/java/com/vectron/fcl/Fcl.java +++ b/src/main/java/com/vectron/fcl/Fcl.java @@ -29,7 +29,7 @@ public class Fcl { private static final String EXIT = "exit"; private final int SCRATCH_SIZE = 1024; private enum Mode { COMPILE, INTERPRET } - private final Dictionary dict = new Dictionary(); + private final Dictionary dict; private final FclStack rstack = new FclStack(); private final JvmInterOp interOp; private final FclStack stack; @@ -47,6 +47,7 @@ public class Fcl { private final String name; private boolean visible = true; private boolean immediate = false; + private Word predicate; public ColonDef(int address, String name) { this.address = address; @@ -70,11 +71,6 @@ public class Fcl { this.visible = isVisible; } - @Override - public boolean visible() { - return visible; - } - @Override public boolean immediate() { return immediate; @@ -85,6 +81,26 @@ public class Fcl { immediate = isImmediate; } + @Override + public void predicate(Word word) { + this.predicate = word; + } + + @Override + public boolean match(String name, Fcl fcl) { + return visible && (this.name.equals(name) || predicateMatch(name, fcl)); + } + + private boolean predicateMatch(String name, Fcl fcl) { + if (predicate == null) return false; + fcl.push(new Str(name)); + predicate.enter(); + boolean match = fcl.pop().boolValue(); + if (match) + fcl.push(new Str(name)); + return match; + } + @Override public String toString() { return "xt_" + name + " (" + address + ")"; @@ -155,11 +171,6 @@ public class Fcl { this.visible = isVisible; } - @Override - public boolean visible() { - return visible; - } - @Override public boolean immediate() { return false; @@ -170,6 +181,16 @@ public class Fcl { throw new Aborted("Cannot make immediate val"); } + @Override + public void predicate(Word word) { + throw new Aborted("var does not support predicate"); + } + + @Override + public boolean match(String name, Fcl fcl) { + return visible && this.name.equals(name); + } + @Override public void enter() { stack.push(new Num(address)); @@ -249,11 +270,6 @@ public class Fcl { this.visible = isVisible; } - @Override - public boolean visible() { - return visible; - } - @Override public boolean immediate() { return false; @@ -264,6 +280,16 @@ public class Fcl { throw new Aborted("Cannot make immediate val"); } + @Override + public void predicate(Word word) { + throw new Aborted("val does not support predicate"); + } + + @Override + public boolean match(String name, Fcl fcl) { + return visible && this.name.equals(name); + } + @Override public void enter() { stack.push(value); @@ -329,6 +355,7 @@ public class Fcl { } public Fcl(FclStack stack, int heapSize, Transcript transcript) { + this.dict = new Dictionary(this); this.stack = stack; this.heap = new Object[heapSize]; this.interOp = new JvmInterOp(stack); @@ -386,6 +413,7 @@ public class Fcl { addPrimitive("here", () -> stack.push(new Num(dp))); addPrimitive("dp!", () -> dp = stack.pop().intValue() ); addPrimitive("interpret", () -> mode = Mode.INTERPRET); + addPrimitive("interpret?", () -> stack.push(mode == Mode.INTERPRET ? Bool.TRUE : Bool.FALSE)); addPrimitive("trace", () -> trace = stack.pop().boolValue()); addPrimitive("lit", () -> stack.push((Obj)heap[ip++])); addPrimitive(">r", () -> rstack.push(stack.pop())); @@ -398,6 +426,8 @@ public class Fcl { addPrimitive("[']", () -> stack.push((Word)heap[ip++])); addPrimitive("`", () -> { Word word = dict.at(word()); stack.push(word == null ? Nil.INSTANCE : word); }); addPrimitive("immediate", () -> dict.lastWord().immediate(true), true); + addPrimitive("lastword", () -> stack.push(dict.lastWord())); + addPrimitive("set-predicate", () -> ((Word)stack.pop()).predicate((Word)stack.pop())); addPrimitive(".", () -> show(stack.pop())); addPrimitive("jvm-call-static", interOp::jvmCallStatic); addPrimitive("jvm-call-method", interOp::jvmCallMethod); @@ -657,6 +687,10 @@ public class Fcl { return stack.pop(); } + public void push(Obj obj) { + stack.push(obj); + } + public int stackSize() { return stack.size(); } diff --git a/src/main/java/com/vectron/fcl/types/Primitive.java b/src/main/java/com/vectron/fcl/types/Primitive.java index 41ef5b7..143ebd0 100644 --- a/src/main/java/com/vectron/fcl/types/Primitive.java +++ b/src/main/java/com/vectron/fcl/types/Primitive.java @@ -1,5 +1,7 @@ package com.vectron.fcl.types; +import com.vectron.fcl.Fcl; +import com.vectron.fcl.exceptions.Aborted; import com.vectron.fcl.exceptions.TypeMismatched; import static com.vectron.fcl.Fcl.STRICT; @@ -21,13 +23,18 @@ public class Primitive implements Word { } @Override - public boolean visible() { - return visible; + public boolean immediate() { + return immediate; } @Override - public boolean immediate() { - return immediate; + public void predicate(Word word) { + throw new Aborted("primitive does not support predicate"); + } + + @Override + public boolean match(String name, Fcl fcl) { + return visible && this.name.equals(name); } @Override diff --git a/src/main/java/com/vectron/fcl/types/Word.java b/src/main/java/com/vectron/fcl/types/Word.java index ffa414c..88aac04 100644 --- a/src/main/java/com/vectron/fcl/types/Word.java +++ b/src/main/java/com/vectron/fcl/types/Word.java @@ -1,10 +1,13 @@ package com.vectron.fcl.types; +import com.vectron.fcl.Fcl; + public interface Word extends Obj { void enter(); String name(); void visible(boolean isVisible); - boolean visible(); boolean immediate(); void immediate(boolean isImmediate); + void predicate(Word word); + boolean match(String name, Fcl fcl); } diff --git a/src/main/res/raw/misc.forth b/src/main/res/raw/misc.forth index 042502b..45cd330 100644 --- a/src/main/res/raw/misc.forth +++ b/src/main/res/raw/misc.forth @@ -13,7 +13,8 @@ } each tbl ; -: ms ( n -- ) 'java.lang.Thread/sleep/l' jvm-call-static ; - +: ms ( n -- ) :java.lang.Thread/sleep/l jvm-call-static ; : tone ( hz ms -- ) swap :com.vectron.forthcalc.support.Tone/play/di jvm-call-static ; -: torch ( n -- ) :com.vectron.forthcalc.support.Torch/toggle/O jvm-call-static ; \ No newline at end of file +: torch ( n -- ) :com.vectron.forthcalc.support.Torch/toggle/O jvm-call-static ; + +: match: immediate ` lastword set-predicate ; \ No newline at end of file diff --git a/src/main/res/raw/plot.forth b/src/main/res/raw/plot.forth index 776cc04..99563aa 100644 --- a/src/main/res/raw/plot.forth +++ b/src/main/res/raw/plot.forth @@ -81,9 +81,10 @@ var: oy 2 LINE-COLOR paint nil => px nil => py 1 => x ls { -> y - x @ y trans 5 draw-circle px @ nil != if px @ py @ trans x @ y trans draw-line + x @ y trans 3 draw-circle + \ 0 x @ y trans 20 + y >str draw-text then x @ px ! y py ! x inc diff --git a/src/test/java/com/vectron/fcl/FclTest.java b/src/test/java/com/vectron/fcl/FclTest.java index db7151b..734d7ef 100644 --- a/src/test/java/com/vectron/fcl/FclTest.java +++ b/src/test/java/com/vectron/fcl/FclTest.java @@ -1236,6 +1236,16 @@ public class FclTest { assertEquals(true, evalPop(": tst :my-symbol :my-symbol = ; tst").boolValue()); } + @Test + public void testPredicateWords() { + eval(": octal? ( token -- ) 0 at '&' = ;\n" + + ": lit-oct ( token -- n ) immediate match: octal?\n" + + " 1 over size substr 8 swap :java.lang.Long/parseLong/si jvm-call-static\n" + + " interpret? not if ['] lit , , then ;\n"); + assertEquals(177, evalPop("&261").intValue()); + assertEquals(169, evalPop(": tst &261 &10 - ; tst ").intValue()); + } + private String transcript() { return transcript.content(); }