]> gitweb.factorcode.org Git - factor.git/commitdiff
ExternalFactor VocabularyLookup
authorSlava Pestov <slava@factorcode.org>
Fri, 19 Nov 2004 04:23:12 +0000 (04:23 +0000)
committerSlava Pestov <slava@factorcode.org>
Fri, 19 Nov 2004 04:23:12 +0000 (04:23 +0000)
TODO.FACTOR.txt
factor/ExternalFactor.java [new file with mode: 0644]
factor/FactorStream.java [new file with mode: 0644]
factor/jedit/ExternalFactor.java [deleted file]
factor/jedit/FactorShell.java
factor/jedit/FactorStream.java [deleted file]
library/tools/jedit-wire.factor

index a1d7d0c74cb2578b90c507c5781982dab8da9f72..501f057df82e3df41f3f82891b1420f6daa71456 100644 (file)
@@ -36,7 +36,7 @@
 - NPE in ErrorHighlight\r
 - some way to not have previous definitions from a source file\r
   clutter the namespace\r
-- ExternalFactor VocabularyLookup\r
+- finish ExternalFactor VocabularyLookup\r
 - fedit broken with listener\r
 - maple-like: press enter at old commands to evaluate there\r
 - completion in the listener\r
@@ -44,6 +44,7 @@
 \r
 + kernel:\r
 \r
+- dissolve library/platform/native/\r
 - profiler is inaccurate: wrong word on cs\r
 - better i/o scheduler\r
 - >lower, >upper for strings\r
diff --git a/factor/ExternalFactor.java b/factor/ExternalFactor.java
new file mode 100644 (file)
index 0000000..6751fd4
--- /dev/null
@@ -0,0 +1,173 @@
+/* :folding=explicit:collapseFolds=1: */
+
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 Slava Pestov.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package factor;
+
+import java.io.*;
+import java.net.Socket;
+import java.util.*;
+import org.gjt.sp.util.Log;
+
+/**
+ * Encapsulates a connection to an external Factor instance.
+ */
+public class ExternalFactor extends DefaultVocabularyLookup
+{
+       //{{{ ExternalFactor constructor
+       /**
+        * We are given two streams that point to a bare REPL.
+        */
+       public ExternalFactor(InputStream in, OutputStream out)
+               throws IOException
+       {
+               this.in = new DataInputStream(in);
+               this.out = new DataOutputStream(out);
+
+               out.write("USE: jedit wire-server\n".getBytes("ASCII"));
+               out.flush();
+
+               waitForAck();
+
+               /* Start stream server */
+               streamServer = 9999;
+               eval("USE: telnetd [ 9999 telnetd ] in-thread");
+       } //}}}
+
+       //{{{ waitForAck() method
+       private void waitForAck() throws IOException
+       {
+               sendEval("\"ACK\" write flush\n");
+
+               /* Read everything until wire header */
+               String discardStr = "";
+
+               while(!discardStr.endsWith("ACK"))
+               {
+                       byte[] discard = new byte[2048];
+                       int len = in.read(discard,0,discard.length);
+                       discardStr = new String(discard,0,len);
+               }
+       } //}}}
+       
+       //{{{ sendEval() method
+       private void sendEval(String cmd) throws IOException
+       {
+               byte[] bytes = cmd.getBytes("ASCII");
+               out.writeInt(bytes.length);
+               out.write(bytes,0,bytes.length);
+               out.flush();
+       } //}}}
+
+       //{{{ eval() method
+       /**
+        * Send a command to the inferior Factor, and return the string output.
+        */
+       public synchronized String eval(String cmd) throws IOException
+       {
+               /* Log.log(Log.DEBUG,ExternalFactor.class,"SEND: " + cmd); */
+
+               waitForAck();
+
+               sendEval(cmd);
+
+               int responseLength = in.readInt();
+               byte[] response = new byte[responseLength];
+               in.readFully(response);
+               
+               String responseStr = new String(response,"ASCII");
+               /* Log.log(Log.DEBUG,ExternalFactor.class,"RECV: " + responseStr); */
+               return responseStr;
+       } //}}}
+
+       //{{{ openStream() method
+       /**
+        * Return a listener stream.
+        */
+       public FactorStream openStream() throws IOException
+       {
+               Socket client = new Socket("localhost",streamServer);
+               return new FactorStream(client);
+       } //}}}
+
+       //{{{ searchVocabulary() method
+       /**
+        * Search through the given vocabulary list for the given word.
+        */
+       public FactorWord searchVocabulary(Cons vocabulary, String name)
+       {
+               FactorWord w = super.searchVocabulary(vocabulary,name);
+               if(w != null)
+                       return w;
+
+               try
+               {
+                       Cons result = parseObject(eval(FactorReader.unparseObject(name)
+                               + " "
+                               + FactorReader.unparseObject(vocabulary)
+                               + " jedit-lookup ."));
+                       if(result.car == null)
+                               return null;
+
+                       result = (Cons)result.car;
+                       return new FactorWord((String)result.car,(String)result.next().car);
+               }
+               catch(Exception e)
+               {
+                       Log.log(Log.ERROR,this,e);
+                       return null;
+               }
+       } //}}}
+
+       //{{{ close() method
+       /**
+        * Close communication session. Factor will then exit.
+        */
+       public synchronized void close()
+       {
+               try
+               {
+                       /* don't care about response */
+                       sendEval("0 exit*");
+                       in.close();
+                       out.close();
+               }
+               catch(Exception e)
+               {
+                       // We don't care...
+                       Log.log(Log.DEBUG,this,e);
+               }
+       } //}}}
+
+       //{{{ Private members
+       private DataInputStream in;
+       private DataOutputStream out;
+       
+       private int streamServer;
+       //}}}
+}
diff --git a/factor/FactorStream.java b/factor/FactorStream.java
new file mode 100644 (file)
index 0000000..6ea2be1
--- /dev/null
@@ -0,0 +1,145 @@
+/* :folding=explicit:collapseFolds=1: */
+
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 Slava Pestov.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package factor;
+
+import javax.swing.text.AttributeSet;
+import java.io.*;
+import java.net.Socket;
+import java.util.*;
+
+/**
+ * Encapsulates a Factor listener connection.
+ */
+public class FactorStream
+{
+       //{{{ FactorStream constructor
+       /**
+        * We are given a socket that points to a bare REPL.
+        */
+       public FactorStream(Socket socket) throws IOException
+       {
+               this.socket = socket;
+               this.in = new DataInputStream(new BufferedInputStream(
+                       socket.getInputStream()));
+               this.out = new DataOutputStream(new BufferedOutputStream(
+                       socket.getOutputStream()));
+
+               out.write("\"\\0\" write flush USE: jedit stream-server\n"
+                       .getBytes("ASCII"));
+               out.flush();
+
+               /* Read everything until prompt */
+               int b = -2;
+               while(b != '\0' && b != -1)
+                       b = in.read();
+       } //}}}
+
+       //{{{ nextPacket() method
+       /**
+        * @return null on EOF.
+        */
+       public Packet nextPacket() throws Exception
+       {
+               int ch = in.read();
+               switch(ch)
+               {
+               case 'r':
+                       return new ReadLinePacket();
+               case 'f':
+                       return new FlushPacket();
+               case 'w':
+                       int len = in.readInt();
+                       byte[] request = new byte[len];
+                       in.readFully(request);
+                       return new WritePacket(new String(request,0,len));
+               case -1:
+                       return null;
+               default:
+                       throw new IOException("Bad stream packet type: " + ch);
+               }
+       } //}}}
+       
+       //{{{ readResponse() method
+       /**
+        * This must only be called if the last packet received was a read request.
+        */
+       public void readResponse(String input) throws IOException
+       {
+               int len = input.length();
+               out.writeInt(len);
+               out.write(input.getBytes("ASCII"),0,len);
+               out.flush();
+       } //}}}
+
+       //{{{ close() method
+       /**
+        * Close communication session. Factor will then exit.
+        */
+       public void close() throws IOException
+       {
+               socket.close();
+               in.close();
+               out.close();
+       } //}}}
+
+       //{{{ Private members
+       private Socket socket;
+       private DataInputStream in;
+       private DataOutputStream out;
+       //}}}
+       
+       //{{{ Packet class
+       public static abstract class Packet {}
+       //}}}
+       
+       //{{{ ReadLinePacket class
+       public static class ReadLinePacket extends Packet {}
+       //}}}
+       
+       //{{{ FlushPacket class
+       public static class FlushPacket extends Packet {}
+       //}}}
+       
+       //{{{ WritePacket class
+       public static class WritePacket extends Packet
+       {
+               public WritePacket(String text)
+                       throws Exception
+               {
+                       this.text = text;
+               }
+               public String getText()
+               {
+                       return text;
+               }
+
+               private String text;
+       } //}}}
+}
diff --git a/factor/jedit/ExternalFactor.java b/factor/jedit/ExternalFactor.java
deleted file mode 100644 (file)
index 7214dfb..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* :folding=explicit:collapseFolds=1: */
-
-/*
- * $Id$
- *
- * Copyright (C) 2004 Slava Pestov.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package factor.jedit;
-
-import factor.*;
-import java.io.*;
-import java.net.Socket;
-import java.util.*;
-import org.gjt.sp.util.Log;
-
-/**
- * Encapsulates a connection to an external Factor instance.
- */
-public class ExternalFactor extends DefaultVocabularyLookup
-{
-       //{{{ ExternalFactor constructor
-       /**
-        * We are given two streams that point to a bare REPL.
-        */
-       public ExternalFactor(InputStream in, OutputStream out)
-               throws IOException
-       {
-               this.in = new DataInputStream(in);
-               this.out = new DataOutputStream(out);
-
-               out.write("USE: jedit wire-server\n".getBytes("ASCII"));
-               out.flush();
-
-               waitForAck();
-
-               /* Start stream server */
-               streamServer = 9999;
-               eval("USE: telnetd [ 9999 telnetd ] in-thread");
-       } //}}}
-
-       //{{{ waitForAck() method
-       private void waitForAck() throws IOException
-       {
-               sendEval("\"ACK\" write flush\n");
-
-               /* Read everything until wire header */
-               String discardStr = "";
-
-               while(!discardStr.endsWith("ACK"))
-               {
-                       byte[] discard = new byte[2048];
-                       int len = in.read(discard,0,discard.length);
-                       discardStr = new String(discard,0,len);
-               }
-       } //}}}
-       
-       //{{{ sendEval() method
-       private void sendEval(String cmd) throws IOException
-       {
-               byte[] bytes = cmd.getBytes("ASCII");
-               out.writeInt(bytes.length);
-               out.write(bytes,0,bytes.length);
-               out.flush();
-       } //}}}
-
-       //{{{ eval() method
-       /**
-        * Send a command to the inferior Factor, and return the string output.
-        */
-       public synchronized String eval(String cmd) throws IOException
-       {
-               waitForAck();
-
-               sendEval(cmd);
-
-               int responseLength = in.readInt();
-               byte[] response = new byte[responseLength];
-               in.readFully(response);
-               
-               return new String(response,"ASCII");
-       } //}}}
-
-       //{{{ openStream() method
-       /**
-        * Return a listener stream.
-        */
-       public FactorStream openStream() throws IOException
-       {
-               Socket client = new Socket("localhost",streamServer);
-               return new FactorStream(client);
-       } //}}}
-
-       //{{{ close() method
-       /**
-        * Close communication session. Factor will then exit.
-        */
-       public synchronized void close()
-       {
-               try
-               {
-                       /* don't care about response */
-                       sendEval("0 exit*");
-                       in.close();
-                       out.close();
-               }
-               catch(Exception e)
-               {
-                       // We don't care...
-                       Log.log(Log.DEBUG,this,e);
-               }
-       } //}}}
-
-       //{{{ Private members
-       private DataInputStream in;
-       private DataOutputStream out;
-       
-       private int streamServer;
-       //}}}
-}
index 264f199360768a2448774dd62d84d51d30d3ca5f..0a464d15850b38c1dd653c55f0277d70a3944f06 100644 (file)
@@ -32,7 +32,7 @@ package factor.jedit;
 import console.*;
 import factor.*;
 import javax.swing.text.AttributeSet;
-import java.io.IOException;
+import java.io.*;
 import java.util.Iterator;
 import java.util.HashMap;
 import org.gjt.sp.jedit.jEdit;
@@ -200,6 +200,19 @@ public class FactorShell extends Shell
                        stream = null;
                }
                
+               private void handleWritePacket(FactorStream.WritePacket w, Output output)
+                       throws Exception
+               {
+                       Cons pair = FactorPlugin.getExternalInstance()
+                               .parseObject(w.getText());
+
+                       String write = (String)pair.car;
+                       AttributeSet attrs = new ListenerAttributeSet(
+                               (Cons)pair.next().car);
+
+                       output.writeAttrs(attrs,write);
+               }
+               
                void packetLoop(Output output) throws Exception
                {
                        if(waitingForInput)
@@ -216,11 +229,7 @@ public class FactorShell extends Shell
                                        break;
                                }
                                else if(p instanceof FactorStream.WritePacket)
-                               {
-                                       FactorStream.WritePacket w
-                                               = (FactorStream.WritePacket)p;
-                                       output.writeAttrs(w.getAttributes(),w.getText());
-                               }
+                                       handleWritePacket((FactorStream.WritePacket)p,output);
                        }
                }
 
diff --git a/factor/jedit/FactorStream.java b/factor/jedit/FactorStream.java
deleted file mode 100644 (file)
index f4ccfa9..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/* :folding=explicit:collapseFolds=1: */
-
-/*
- * $Id$
- *
- * Copyright (C) 2004 Slava Pestov.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- *    this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package factor.jedit;
-
-import factor.Cons;
-import factor.FactorReader;
-import javax.swing.text.AttributeSet;
-import java.io.*;
-import java.net.Socket;
-import java.util.*;
-
-/**
- * Encapsulates a Factor listener connection.
- */
-public class FactorStream
-{
-       //{{{ FactorStream constructor
-       /**
-        * We are given a socket that points to a bare REPL.
-        */
-       public FactorStream(Socket socket) throws IOException
-       {
-               this.socket = socket;
-               this.in = new DataInputStream(new BufferedInputStream(
-                       socket.getInputStream()));
-               this.out = new DataOutputStream(new BufferedOutputStream(
-                       socket.getOutputStream()));
-
-               out.write("\"\\0\" write flush USE: jedit stream-server\n"
-                       .getBytes("ASCII"));
-               out.flush();
-
-               /* Read everything until prompt */
-               int b = -2;
-               while(b != '\0' && b != -1)
-                       b = in.read();
-       } //}}}
-
-       //{{{ nextPacket() method
-       /**
-        * @return null on EOF.
-        */
-       public Packet nextPacket() throws Exception
-       {
-               int ch = in.read();
-               switch(ch)
-               {
-               case 'r':
-                       return new ReadLinePacket();
-               case 'f':
-                       return new FlushPacket();
-               case 'w':
-                       int len = in.readInt();
-                       byte[] request = new byte[len];
-                       in.readFully(request);
-                       return new WritePacket(new String(request,0,len));
-               case -1:
-                       return null;
-               default:
-                       throw new IOException("Bad stream packet type: " + ch);
-               }
-       } //}}}
-       
-       //{{{ readResponse() method
-       /**
-        * This must only be called if the last packet received was a read request.
-        */
-       public void readResponse(String input) throws IOException
-       {
-               int len = input.length();
-               out.writeInt(len);
-               out.write(input.getBytes("ASCII"),0,len);
-               out.flush();
-       } //}}}
-
-       //{{{ close() method
-       /**
-        * Close communication session. Factor will then exit.
-        */
-       public void close() throws IOException
-       {
-               socket.close();
-               in.close();
-               out.close();
-       } //}}}
-
-       //{{{ Private members
-       private Socket socket;
-       private DataInputStream in;
-       private DataOutputStream out;
-       //}}}
-       
-       //{{{ Packet class
-       public static abstract class Packet {}
-       //}}}
-       
-       //{{{ ReadLinePacket class
-       public static class ReadLinePacket extends Packet {}
-       //}}}
-       
-       //{{{ FlushPacket class
-       public static class FlushPacket extends Packet {}
-       //}}}
-       
-       //{{{ WritePacket class
-       public static class WritePacket extends Packet
-       {
-               public WritePacket(String input)
-                       throws Exception
-               {
-                       FactorReader parser = new FactorReader(
-                               "parseObject()",
-                               new BufferedReader(new StringReader(input)),
-                               true,FactorPlugin.getExternalInstance());
-                       Cons pair = parser.parse();
-
-                       this.write = (String)pair.car;
-                       this.attrs = new ListenerAttributeSet((Cons)pair.next().car);
-               }
-               
-               public String getText()
-               {
-                       return write;
-               }
-
-               public AttributeSet getAttributes()
-               {
-                       return attrs;
-               }
-
-               private String write;
-               private AttributeSet attrs;
-       } //}}}
-}
index 7c2cd7af9e3dfdca5afde9ba57fc7ab856d715de..682791508e473bb41f6d5a58adf52f5daacdedc9 100644 (file)
 ! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 IN: jedit
-USE: stdio
-USE: stack
-USE: strings
 USE: combinators
-USE: parser
+USE: lists
 USE: namespaces
+USE: parser
 USE: presentation
-USE: streams
 USE: prettyprint
+USE: stack
+USE: stdio
+USE: streams
+USE: strings
+USE: words
 
 ! Wire protocol for jEdit to evaluate Factor code.
 ! Packets are of the form:
@@ -101,3 +103,16 @@ USE: prettyprint
 : stream-server ( -- )
     #! Execute this in the inferior Factor.
     "stdio" get <jedit-stream> "stdio" set ;
+
+: jedit-lookup ( word vocabs -- )
+    #! A utility word called by the Factor plugin to get some
+    #! required word info.
+    search dup [
+        [
+            "vocabulary"
+            "name"
+            "stack-effect"
+        ] [
+            dupd word-property
+        ] map nip
+    ] when ;