author | Alan Dipert
<alan@dipert.org> 2019-08-13 16:17:45 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-08-13 16:17:45 UTC |
parent | 11a36fadd9de5bdd13f16b0272313beeb7806a5d |
jacl.js | +35 | -14 |
diff --git a/jacl.js b/jacl.js index 632c4e1..01c36f8 100644 --- a/jacl.js +++ b/jacl.js @@ -57,15 +57,31 @@ class LispSymbol { popBinding() { this.value = this.stack.pop(); } + static intern(packageName, name) { + if (readInteger(packageName)) + throw new Error(`Symbol package must not be number: '${packageName}'`); + if (readInteger(name)) + throw new Error(`Symbol name must not be number: '${name}'`); + return Package.get(packageName, true).intern(name); + } static fromString(token) { if (/^:[^:]+$/.test(token)) { - const kw = token.substring(1); - if (readInteger(kw)) - throw new Error(`Must not have number syntax after ':': '${token}'`); - return Package.get('KEYWORD').intern(kw) - } else { - throw new Error(`TODO: other symbols`); + return LispSymbol.intern('KEYWORD', token.substring(1)); + } + + const singleMarkerRe = /^([^:]+):([^:]+)$/; + const doubleMarkerRe = /^([^:]+)::([^:]+)$/; + + for (const re of [singleMarkerRe, doubleMarkerRe]) { + const match = token.match(re); + if (match) return LispSymbol.intern(...match.slice(1)); } + + if (token.indexOf(':') < 0) { + return PACKAGE.val().intern(token); + } + + throw new Error(`Unknown symbol syntax: '${token}'`); } } @@ -98,8 +114,12 @@ class Package { if (this.name === 'KEYWORD') this.exports.set(name, sym); return sym; } - static get(packageName) { - return PACKAGES.get(packageName) || null; + static get(packageName, throwNotFound = false) { + const pkg = PACKAGES.get(packageName); + if (!pkg && throwNotFound) { + throw new Error(`Package '${packageName}' does not exist`); + } + return pkg; } static makePackage(name, ...aliases) { const newPackage = new Package(name); @@ -108,10 +128,13 @@ class Package { } } -Package.makePackage('JSCL'); +Package.makePackage('JACL'); Package.makePackage('CL', 'COMMON-LISP'); Package.makePackage('KEYWORD'); +const PACKAGE = Package.get('CL').intern('*PACKAGE*'); +PACKAGE.value = Package.get('CL'); + class BufferedStream { constructor() { this.buf = []; @@ -177,20 +200,18 @@ READTABLE.value = new ReadTable() } }) .setMacro('"', true, async function(stream) { - let str = ''; + let str = new LispString(); for await(const x of stream) { if (x === '"') { return new Values(str); } else if(x === '\\') { - str += await stream.read(); + str.push(await stream.read()); } else { - str += x; + str.push(x); } } }); -//const isTerminating = ch => '\")(`,\';'.indexOf(ch) > -1; - const isWhitespace = ch => ' \t\n\r\b'.indexOf(ch) > -1; const isConstituent = ch => {