git » jacl.git » commit 93590b0

Clean up list reading; eliminate Token type; remove reader macros to support list reading

author Alan Dipert
2019-08-29 04:00:13 UTC
committer Alan Dipert
2019-08-29 04:00:13 UTC
parent 8bd3cb210c9f3aa7a0d4d2c68dc53f15ae43cbf0

Clean up list reading; eliminate Token type; remove reader macros to support list reading

jacl.js +56 -52

diff --git a/jacl.js b/jacl.js
index 3ea7850..033c4c0 100644
--- a/jacl.js
+++ b/jacl.js
@@ -223,70 +223,76 @@ class ReadTable {
 
 const READTABLE = Package.intern('CL', '*READTABLE*');
 
-class Token extends String {
-  interpret() {
-    const prim = this.valueOf();
+const interpretToken = str => {
+  const [isInt, intVal] = readInteger(str);
+  if (isInt) return intVal;
 
-    const [isInt, intVal] = readInteger(prim);
-    if (isInt) return intVal;
+  return LispSymbol.internFromString(str);
+};
 
-    return LispSymbol.internFromString(prim);
+const skipWhitespace = async stream => {
+  for await(const ch of stream) {
+    if (!isWhitespace(ch)) {
+      stream.unread(ch);
+      return;
+    }
   }
-  static is(x, y) {
-    return (x instanceof Token) && x.valueOf() === y;
+};
+
+const dotIsNext = async stream => {
+  const x = await stream.read(),
+        y = await stream.read();
+
+  if (x === '.' && isWhitespace(y)) {
+    return true;
+  } else {
+    stream.unread(y);
+    stream.unread(x);
+    return false;
   }
-}
+};
 
-const safeRead = async rdr => {
-  var x;
-  try {
-    x = await rdr.read();
-  } catch (e) {
-    if (e instanceof DotError || e instanceof CloseParenError) {
-      return e;
-    }
-    throw e;
+const closeParenIsNext = async stream => {
+  const x = await stream.read();
+  if (x === ')') {
+    return true;
+  } else {
+    stream.unread(x);
+    return false;
   }
-  return x;
-}
+};
 
 const readList = async stream => {
-  const rdr = new Reader(stream),
-        x   = await safeRead(rdr);
 
-  if (x instanceof DotError)
-    throw new Error(`Nothing before . in list`);
+  const rdr = new Reader(stream);
 
-  if (x instanceof CloseParenError)
+  await skipWhitespace(stream);
+
+  if (await closeParenIsNext(stream))
     return new Values(null);
 
-  const car   = x,
-        after = await safeRead(rdr);
+  if (await dotIsNext(stream))
+    throw new Error(`Nothing before . in list`);
 
-  if (after instanceof DotError) {
-    const y = await safeRead(rdr);
-    if (y instanceof Error)
-      throw new Error(`Nothing after . in list`);
-    const cons = new Cons(car, y);
-    if ((await safeRead(rdr)) instanceof CloseParenError) {
-      return new Values(cons);
-    } else {
-      throw new Error(`More than one object after . in list`);
-    }
-  }
+  const car = await rdr.read();
 
-  if (after instanceof CloseParenError)
-    return new Values(new Cons(car));
+  await skipWhitespace(stream);
 
-  return new Values(new Cons(car, new Cons(after, (await readList(stream))[0])));
-}
+  if (await closeParenIsNext(stream))
+    return new Values(new Cons(car));
 
-class DotError extends Error {
-  constructor() { super('. context error'); }
-}
+  if (await dotIsNext(stream)) {
+    await skipWhitespace(stream);
+    if (await closeParenIsNext(stream))
+      throw new Error(`Nothing after . in list`);
+    const cdr = await rdr.read();
+    await skipWhitespace(stream);
+    if (await closeParenIsNext(stream))
+      return new Values(new Cons(car, cdr));
+    throw new Error(`More than one object after . in list`);
+  }
 
-class CloseParenError extends Error {
-  constructor() { super('Unmatched )'); }
+  return new Values(new Cons(car, (await readList(stream))[0]));
 }
 
 READTABLE.value = new ReadTable()
@@ -307,13 +313,11 @@ READTABLE.value = new ReadTable()
       }
     }
   })
-  .setMacro('.', false, async stream => { throw new DotError(); })
-  .setMacro(')', true, async stream => { throw new CloseParenError(); })
   .setMacro('(', true, readList)
   .setMacro("'", true, async stream => {
     return new Values(Cons.listOf(
       Package.intern('CL', 'QUOTE'),
-      await Reader.of(Tokenizer.of(stream)).read()
+      await (new Reader(stream)).read()
     ));
   });
 
@@ -359,9 +363,9 @@ const readSingleEscaped = async function(stream, token) {
       continue;
     } else if (y === '|') {
       return readMultiEscaped(stream, token);
-    } else if (READTABLE.val().isTerminating(y) || isWhitespace(y)) {
+    } else if (READTABLE.val().isTerminating(y) || isWhitespace(y) || y === ')') {
       stream.unread(y);
-      return new Token(token).interpret();
+      return interpretToken(token);
     } else {
       throw new Error(`Illegal character: '${y}'`);
     }