author | Alan Dipert
<alan@dipert.org> 2020-03-24 05:19:54 UTC |
committer | Alan Dipert
<alan@dipert.org> 2020-03-24 05:19:54 UTC |
parent | 5df3cfc829e178bb79e1e3c862db028badef4e8a |
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}'`); }