git » jacl.git » commit 205dd97

mValues can't be async; use ReadValues tuple for read macros and findSymbol

author Alan Dipert
2021-06-27 06:35:54 UTC
committer Alan Dipert
2021-06-27 06:35:54 UTC
parent 9e30939de3d835de58f836bdd8e69dab4887bf84

mValues can't be async; use ReadValues tuple for read macros and findSymbol

jacl.js +53 -36

diff --git a/jacl.js b/jacl.js
index 413449e..607e950 100644
--- a/jacl.js
+++ b/jacl.js
@@ -237,9 +237,9 @@ class LispSymbol {
     }
   }
   static intern(packageName, name) {
-    if (readInteger(packageName))
+    if (readInteger(packageName).first())
       throw new Error(`Symbol package must not be number: '${packageName}'`);
-    if (readInteger(name))
+    if (readInteger(name).first())
       throw new Error(`Symbol name must not be number: '${name}'`);
     return Package.get(packageName, true).intern(name);
   }
@@ -307,7 +307,7 @@ class LispSymbol {
       } else {
         // The symbol isn't qualified, so first attempt to resolve it using
         // information stored in the current package.
-        const sym = PACKAGE.val().findSymbol(name, false);
+        const sym = PACKAGE.val().findSymbol(name, false).first();
         // If the symbol wasn't found, intern in the current package.
         return sym ? sym : PACKAGE.val().intern(name);
       }
@@ -370,7 +370,7 @@ class Package {
   }
   findSymbol(name) {
     if (this.symbols.has(name)) {
-      return mValues(
+      return new ReadValues(
         this.symbols.get(name),
         LispSymbol.kw(this.exports.has(name) ? 'external' : 'internal')
       );
@@ -378,14 +378,14 @@ class Package {
 
     for (const usedPkg of this.use) {
       if (usedPkg.isExported(name)) {
-        return mValues(
+        return new ReadValues(
           usedPkg.symbols.get(name),
           LispSymbol.kw('inherited')
         );
       }
     }
 
-    return mValues(null, null);
+    return new ReadValues(null, null);
   }
   static intern(packageName, name) {
     const pkg = Package.get(packageName, true);
@@ -492,6 +492,25 @@ JACLPKG.usePackage(CLPKG);
 
 // Multiple values
 
+// faux read macros, async friendly
+class ReadValues {
+  constructor(...vals) {
+    this.vals = vals;
+  }
+  [Symbol.iterator]() {
+    return this.vals[Symbol.iterator]();
+  }
+  first() {
+    if (this.vals.length < 1) throw new Error("No first value");
+    return this.vals[0];
+  }
+  second() {
+    if (this.vals.length < 2) throw new Error("No second value");
+    return this.vals[1];
+  }
+}
+
+// real
 const MV_EXPECTED = JACLPKG.intern("*MV-EXPECTED*")
 MV_EXPECTED.isSpecial = true;
 MV_EXPECTED.value = 1;
@@ -626,7 +645,7 @@ class ReadTable {
 const READTABLE = Package.intern('CL', '*READTABLE*');
 
 const interpretToken = (token, intern) => {
-  const [isInt, intVal] = mvArray(() => readInteger(token.str), 2);
+  const [isInt, intVal] = readInteger(token.str);
   if (isInt) return intVal;
   const sym = LispSymbol.createFromString(token, intern);
   if (eqClSym(sym, 'NIL')) {
@@ -653,7 +672,7 @@ const readList = async stream => {
     throw new Error(`Nothing before . in list`);
 
   if (x === listSentinels.get(')'))
-    return null;
+    return new ReadValues(null);
 
   car = x;
 
@@ -666,21 +685,21 @@ const readList = async stream => {
     const cdr = x;
     x = await rdr.read(true, listSentinels);
     if (x === listSentinels.get(')'))
-      return new Cons(car, cdr);
+      return new ReadValues(new (Cons(car, cdr)));
     throw new Error(`More than one object after . in list`);
   }
 
   if (x === listSentinels.get(')'))
-    return new Cons(car);
+    return new ReadValues(new Cons(car));
 
-  return new Cons(car, new Cons(x, (await readList(stream))[0]));
+  return new ReadValues(new Cons(car, new Cons(x, (await readList(stream)).first())));
 }
 
 const readString = async stream => {
   let str = new LispString();
   for await(const x of stream) {
     if (x === '"') {
-      return str;
+      return new ReadValues(str);
     } else if(x === '\\') {
       str.push(await stream.read());
     } else {
@@ -692,60 +711,60 @@ const readString = async stream => {
 // TODO make this a real JS string reader
 const readJsString = async stream => {
   const [clStr] = await readString(stream);
-  return clStr.toString();
+  return new ReadValues(clStr.toString());
 };
 
 const readGlobalReference = async stream => {
   const sym = await readMultiEscaped(stream, new Token().sawPipe(), false),
         parts = sym.name.split('.'),
         [topic, ...fields] = parts;
-  return Cons.listOf(
+  return new ReadValues(Cons.listOf(
     JACLPKG.intern('.'),
     Cons.listOf(JACLPKG.intern('%JS'), topic),
     ...fields.map(x => new LispSymbol(x, null))
-  );
+  ));
 };
 
 const readAwait = async stream => {
-  return Cons.listOf(
+  return new ReadValues(Cons.listOf(
     JACLPKG.intern('AWAIT'),
     await (new Reader(stream)).read()
-  );
+  ));
 }
 
 READTABLE.value = new ReadTable()
   .setMacro(';', true, async stream => {
     for await(const ch of stream) {
-      if (ch === '\n') return mValues();
+      if (ch === '\n') return new ReadValues();
     }
   })
   .setMacro('"', true, readString)
   .setMacro('(', true, readList)
   .setMacro("'", true, async stream => {
-    return Cons.listOf(
+    return new ReadValues(Cons.listOf(
       Package.intern('CL', 'QUOTE'),
       await (new Reader(stream)).read()
-    );
+    ));
   })
   .setMacro("`", true, async stream => {
-    return Cons.listOf(
+    return new ReadValues(Cons.listOf(
       JACLPKG.intern('QUASIQUOTE'),
       await new Reader(stream).read()
-    );
+    ));
   })
   .setMacro(',', true, async stream => {
     const ch = await stream.read();
     if (ch === '@') {
-      return Cons.listOf(
+      return new ReadValues(Cons.listOf(
         JACLPKG.intern('UNQUOTE-SPLICING'),
         await new Reader(stream).read()
-      );
+      ));
     } else {
       stream.unread(ch);
-      return Cons.listOf(
+      return new ReadValues(Cons.listOf(
         JACLPKG.intern('UNQUOTE'),
         await new Reader(stream).read()
-      );
+      ));
     }
   })
   .makeDispatchMacroChar('#', true)
@@ -753,7 +772,7 @@ READTABLE.value = new ReadTable()
     const rdr = new Reader(stream),
           sym = await rdr.read(false);
     if (sym instanceof LispSymbol && sym.packageName === null) {
-      return sym;
+      return new ReadValues(sym);
     } else if (sym instanceof LispString && sym.packageName !== null) {
       throw new Error(`Object after #: contains a package marker`);
     } else {
@@ -761,16 +780,16 @@ READTABLE.value = new ReadTable()
     }
   })
   .setDispatchMacroChar('#', '\\', async stream => {
-    return await stream.read();
+    return new ReadValues(await stream.read());
   })
   .setDispatchMacroChar('#', '<', async stream => {
     throw new Error(`Illegal # char: <`);
   })
   .setDispatchMacroChar('#', "'", async stream => {
-    return Cons.listOf(
+    return new ReadValues(Cons.listOf(
       Package.intern('CL', 'FUNCTION'),
       await (new Reader(stream)).read()
-    );
+    ));
   });
 
 const isWhitespace = ch => ' \t\n\r\b'.indexOf(ch) > -1;
@@ -861,9 +880,9 @@ const readMultiEscaped = async function(stream, token, intern = true) {
 
 const readInteger = token => {
   if (/^[+-]?[0-9]+\.?$/.test(token)) {
-    return mValues(true, window.parseInt(token));
+    return new ReadValues(true, window.parseInt(token));
   } else {
-    return mValues(false, null);
+    return new ReadValues(false, null);
   }
 };
 
@@ -903,13 +922,11 @@ class Reader {
       } else if (isWhitespace(x)) {
         continue;
       } else if (macroFun = READTABLE.val().getMacro(x)) {
-        // const vals = await macroFun(this.stream);
-        const vals = mvArray(() => macroFun(this.stream));
-        console.log(vals);
+        const vals = [...await macroFun(this.stream)];
         if (vals.length) {
           return vals[0];
         } else {
-          continue
+          continue;
         }
       } else if (x === '\\') {
         let y = new Token(await this.stream.read());