author | Alan Dipert
<alan@dipert.org> 2019-08-29 04:00:13 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-08-29 04:00:13 UTC |
parent | 8bd3cb210c9f3aa7a0d4d2c68dc53f15ae43cbf0 |
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}'`); }