author | Alan Dipert
<alan@dipert.org> 2019-08-22 06:08:33 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-08-22 06:08:33 UTC |
parent | cc3687511e8118645700f45a6a49ac639f05906e |
jacl-tests.js | +69 | -94 |
jacl.js | +6 | -4 |
diff --git a/jacl-tests.js b/jacl-tests.js index 0897fb6..cc71552 100644 --- a/jacl-tests.js +++ b/jacl-tests.js @@ -1,101 +1,76 @@ QUnit.config.testTimeout = 100; // milliseconds -QUnit.module("reader"); +QUnit.module('Reader'); + +const makeRead1 = (rdr, it) => { + return async str => { + const done = it.async(); + rdr.tokenizer.stream.writeEach(str); + const obj = await rdr.read(); + done(); + return obj; + } +}; + +QUnit.test('Integers', async is => { + const rdr = Reader.of(Tokenizer.of(new BufferedStream())), + read1 = makeRead1(rdr, is); + + is.strictEqual(await read1('123 '), 123, 'single integer'); + is.strictEqual(await read1('+9912 '), 9912, 'integer with leading +'); + is.strictEqual(await read1('0 '), 0, 'zero'); + is.strictEqual(await read1('-32 '), -32, 'negative number'); + is.strictEqual(await read1('1. '), 1, 'number with trailing dot'); +}); + +QUnit.test('Symbols', async is => { + const rdr = Reader.of(Tokenizer.of(new BufferedStream())), + read1 = makeRead1(rdr, is); + var sym; + + sym = await read1('defun '); + is.strictEqual(sym.name, 'DEFUN', 'simple symbol name'); + is.strictEqual(sym.packageName, 'COMMON-LISP', 'simple symbol package'); + + sym = await read1('|Alan| '); + is.strictEqual(sym.name, 'Alan', 'simple symbol name'); + + sym = await read1(String.raw`\alan `); + is.strictEqual(sym.name, 'aLAN', 'simple symbol with escape'); + + Package.makePackage('TEST-PACKAGE'); + + sym = await read1('test-package::+ '); + is.strictEqual(sym.name, '+', 'exported symbol'); + is.strictEqual(sym.packageName, 'TEST-PACKAGE', 'exported symbol'); + + // TODO external vs internal + sym = await read1('|TEST-PACKAGE::some symbol| '); + is.strictEqual(sym.name, 'some symbol', 'pipe/qualified symbol'); + is.strictEqual(sym.packageName, 'TEST-PACKAGE', 'pipe/qualified symbol'); + + sym = await read1(':some-lil-kw '); + is.strictEqual(sym.name, 'SOME-LIL-KW', 'kw name'); + is.strictEqual(sym.packageName, 'KEYWORD', 'kw package'); -QUnit.test("works", is => { - is.ok(true); }); -//QUnit.test("single integer", is => { -// const done = is.async(); -// new Reader(x => { -// is.ok(x instanceof Number); -// is.equal(x, 123); -// done(); -// }).readString("123 "); -//}); -// -//QUnit.test("single integer with multiple readString", is => { -// const done = is.async(); -// const rdr = new Reader(x => { -// is.ok(x instanceof Number); -// is.equal(x, 123); -// done(); -// }); -// rdr.readString("1"); -// rdr.readString("23"); -// rdr.readString(" "); -//}); -// -//QUnit.test("whitespace is ignored", is => { -// const done = is.async(); -// const rdr = new Reader(x => { -// is.ok(x instanceof Number); -// is.equal(x, 123); -// done(); -// }); -// rdr.readString("\n \n\t "); -// rdr.readString("123"); -// rdr.readString("(\t \n "); -//}); -// -//QUnit.test("() is nil", is => { -// const done = is.async(); -// new Reader(x => { -// is.strictEqual(x, null); -// done(); -// }).readString("()"); -//}); -// -//QUnit.test("nested lists", is => { -// const done = is.async(); -// new Reader(x => { -// is.ok(x instanceof Cons); -// is.strictEqual(x.car, null); -// is.equal(x.cdr.car.car, 1); -// is.strictEqual(x.cdr.cdr.car.car.car, null); -// done(); -// }).readString("(() (1) ((())))"); -//}); -// -//QUnit.test("Array.from proper lists", is => { -// const done = is.async(); -// new Reader(x => { -// is.deepEqual(Array.from(x), [1, 2, 3]); -// done(); -// }).readString("(1 2 3)"); -//}); -// -//QUnit.test("Array.from pairs", is => { -// const done = is.async(); -// new Reader(x => { -// is.deepEqual(Array.from(x), [1, 2]); -// done(); -// }).readString("(1 . 2)"); -//}); -// -//QUnit.test("unexpected after dot", is => { -// const done = is.async(); -// new Reader(x => {}, err => { -// is.ok(err.match(/Unexpected element after dot/)); -// done(); -// }).readString("(1 . 2 3)"); -//}); -// -//QUnit.only("nothing after dot", is => { -// const done = is.async(); -// new Reader(x => {}, err => { -// is.ok(err.match(/No element after dot/)); -// done(); -// }).readString("(1 . )"); -//}); -// -//QUnit.test("Array.from compound structure", is => { -// const done = is.async(); -// new Reader(x => { -// is.deepEqual(Array.from(x), [[1, 2], [3, 4]]); -// done(); -// }).readString("((1 . 2) (3 . 4))"); -//}); +QUnit.test('Conses', async is => { + const rdr = Reader.of(Tokenizer.of(new BufferedStream())), + read1 = makeRead1(rdr, is); + var cons; + cons = await read1('()'); + is.strictEqual(cons, null, 'nil'); + cons = await read1('(1)'); + is.strictEqual(cons.car, 1, 'car of cons'); + is.strictEqual(cons.cdr, null, 'cdr of cons'); + + cons = await read1('(1 . 2)'); + is.strictEqual(cons.car, 1, 'car of dot cons'); + is.strictEqual(cons.cdr, 2, 'cdr of dot cons'); + + // TODO dot syntax parse error tests + +}); diff --git a/jacl.js b/jacl.js index c9ba5e8..db77f35 100644 --- a/jacl.js +++ b/jacl.js @@ -63,9 +63,9 @@ class LispSymbol { this.value = this.stack.pop(); } static intern(packageName, name) { - if (readInteger(packageName)) + if (readInteger(packageName)[0]) throw new Error(`Symbol package must not be number: '${packageName}'`); - if (readInteger(name)) + if (readInteger(name)[0]) throw new Error(`Symbol name must not be number: '${name}'`); return Package.get(packageName, true).intern(name); } @@ -127,7 +127,8 @@ const PACKAGES = new Map(); class Token extends String { interpret() { - return readInteger(this) || LispSymbol.fromString(this); + const [isInteger, i] = readInteger(this); + return isInteger ? i : LispSymbol.fromString(this); } static is(x, y) { return (x instanceof Token) && x.valueOf() === y; @@ -348,8 +349,9 @@ const readMultiEscaped = async function(stream, token) { const readInteger = token => { if (/^[+-]?[0-9]+\.?$/.test(token)) { - return window.parseInt(token); + return new Values(true, window.parseInt(token)); } + return new Values(false); }; const readSingleEscaped = async function(stream, token) {