git » jacl.git » commit c9d44ec

Significant list reader cleanup

author Alan Dipert
2020-03-24 05:19:54 UTC
committer Alan Dipert
2020-03-24 05:19:54 UTC
parent 5df3cfc829e178bb79e1e3c862db028badef4e8a

Significant list reader cleanup

jacl.js +24 -46

diff --git a/jacl.js b/jacl.js
index 91062d5..1378de1 100644
--- a/jacl.js
+++ b/jacl.js
@@ -573,67 +573,43 @@ const interpretToken = (token, intern) => {
   return LispSymbol.createFromString(token, intern);
 };
 
-const skipWhitespace = async stream => {
-  for await(const ch of stream) {
-    if (!isWhitespace(ch)) {
-      stream.unread(ch);
-      return;
-    }
-  }
-};
-
-const dotIsNext = async stream => {
-  await skipWhitespace(stream);
-  const x = await stream.read();
-
-  if (x !== '.') {
-    stream.unread(x);
-    return false;
-  }
-
-  const y = await stream.read();
-
-  if (isWhitespace(y)) return true;
-
-  stream.unread(y);
-  stream.unread(x);
-  return false;
-};
+const readList = async stream => {
 
-const closeParenIsNext = async stream => {
-  await skipWhitespace(stream);
-  const x = await stream.read();
-  if (x === ')') return true;
-  stream.unread(x);
-  return false;
-};
+  const rdr = new Reader(stream),
+        sentinels = new Map([
+          ['.', new Object()],
+          [')', new Object()]
+        ]);
 
-const readList = async stream => {
+  let x, car, cdr;
 
-  const rdr = new Reader(stream);
+  x = await rdr.read(true, sentinels);
 
-  if (await dotIsNext(stream))
+  if (x === sentinels.get('.'))
     throw new Error(`Nothing before . in list`);
 
-  if (await closeParenIsNext(stream))
+  if (x === sentinels.get(')'))
     return new Values(null);
 
-  const car = await rdr.read();
+  car = x;
+
+  x = await rdr.read(true, sentinels);
 
-  if (await dotIsNext(stream)) {
-    await skipWhitespace(stream);
-    if (await closeParenIsNext(stream))
+  if (x === sentinels.get('.')) {
+    x = await rdr.read(true, sentinels);
+    if (x === sentinels.get(')'))
       throw new Error(`Nothing after . in list`);
-    const cdr = await rdr.read();
-    if (await closeParenIsNext(stream))
+    cdr = x;
+    x = await rdr.read(true, sentinels);
+    if (x === sentinels.get(')'))
       return new Values(new Cons(car, cdr));
     throw new Error(`More than one object after . in list`);
   }
 
-  if (await closeParenIsNext(stream))
+  if (x === sentinels.get(')'))
     return new Values(new Cons(car));
 
-  return new Values(new Cons(car, (await readList(stream))[0]));
+  return new Values(new Cons(car, new Cons(x, (await readList(stream))[0])));
 }
 
 const readString = async stream => {
@@ -854,7 +830,7 @@ class Reader {
   static of(stream) {
     return new Reader(stream);
   }
-  async read(internSymbols = true) {
+  async read(internSymbols = true, charSentinels = new Map()) {
     let macroFun;
     for await(const x of this.stream) {
       if (x === EOF) {
@@ -875,6 +851,8 @@ class Reader {
         return readMultiEscaped(this.stream, new Token().sawPipe(), internSymbols);
       } else if (isConstituent(x)) {
         return readSingleEscaped(this.stream, new Token(x.toUpperCase()), internSymbols);
+      } else if (charSentinels.has(x)) {
+        return charSentinels.get(x);
       } else {
         throw new Error(`Illegal character: '${x}'`);
       }