author | Alan Dipert
<alan@dipert.org> 2019-10-18 13:20:41 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-18 13:20:41 UTC |
parent | 488651d32f1dbea7a7c35fbf48007345de6bebc9 |
jacl.js | +32 | -54 |
diff --git a/jacl.js b/jacl.js index 3dabc5d..2a8f00f 100644 --- a/jacl.js +++ b/jacl.js @@ -70,6 +70,7 @@ class LispSymbol { this.fvalue = UNDEFINED; this.stack = []; this.isMacro = false; + this.isConstant = false; } val() { if (this.value === UNDEFINED) @@ -85,6 +86,10 @@ class LispSymbol { this.isMacro = true; return this; } + setConstant() { + this.isConstant = true; + return this; + } pushBinding(v) { this.stack.push(this.value); this.value = v; @@ -95,6 +100,23 @@ class LispSymbol { getPackage() { return Package.get(this.packageName); } + static bindSpecial(syms, vals, thunk) { + try { + for (let i = 0; i < syms.length; i++) { + const sym = syms[i]; + if (sym.isConstant) { + throw new Error(`Can't bind constant`); + } + sym.stack.push(sym.value); + sym.value = vals[i]; + } + return thunk(); + } finally { + for (let i = 0; i < syms.length; i++) { + syms[i].value = syms[i].stack.pop(); + } + } + } static intern(packageName, name) { if (readInteger(packageName)[0]) throw new Error(`Symbol package must not be number: '${packageName}'`); @@ -269,12 +291,12 @@ Package.makePackage('KEYWORD'); // CL package constants // TODO update this, look into constants const CLCONSTS = new Map([ - ['T', 'true'], - ['NIL', 'null'] + ['T', true], + ['NIL', null] ]); for (const [k,v] of CLCONSTS) { - CLPKG.intern(k); + CLPKG.intern(k).setConstant().value = v; CLPKG.exportSymbol(k); } @@ -292,16 +314,16 @@ for (const [k,v] of CLFUNCS) { // JS package constants const JSCONSTS = new Map([ - ['+FALSE+', 'false'], - ['+NAN+', 'NaN'], - ['+NULL+', 'null'], - ['+TRUE+', 'true'], - ['+UNDEFINED+', 'undefined'], - ['+THIS+', 'this'] + ['+FALSE+', false], + ['+NAN+', NaN], + ['+NULL+', null], + ['+TRUE+', true], + ['+UNDEFINED+', undefined], + ['+THIS+', this] ]); for (const [k,v] of JSCONSTS) { - JSPKG.intern(k); + JSPKG.intern(k).setConstant().value = v; JSPKG.exportSymbol(k); } @@ -694,35 +716,6 @@ for (const s of ['%DOT', '%CALL', '%LAMBDA']) { JACLPKG.intern(s); } -// Primitive functions related to interop -JACLPKG.intern('TO-JS').fvalue = x => { - if (x instanceof LispString) { - return x.toString(); - } else { - throw new Error(`Don't know how to convert ${x} to a JS value`); - } -}; -JACLPKG.exportSymbol('TO-JS'); - -JACLPKG.intern('.').setMacro().fvalue = function(topic, ...ops) { - if (arguments.length < 2) throw new Error(`\. requires at least two arguments`); - return ops.reduce((prev, op) => { - if (op instanceof LispSymbol) { - return Cons.listOf(JACLPKG.intern('%DOT'), prev, op); - } else if (op instanceof Cons) { - const [method, ...args] = op; - return Cons.listOf( - JACLPKG.intern('%CALL'), - Cons.listOf(JACLPKG.intern('%DOT'), prev, method), - ...args - ); - } else { - throw new Error(`Invalid \. syntax: ${op}`); - } - }, topic); -}; -JACLPKG.exportSymbol('.'); - CLPKG.intern('QUOTE').setMacro().fvalue = function(env, form, x) { return Cons.listOf(JACLPKG.intern('%QUOTE'), x); }; @@ -791,21 +784,6 @@ JACLPKG.intern('QUASIQUOTE').setMacro().fvalue = function(env, form) { return expand(form); }; -const readJsString = async stream => { - // TODO make this a real JS string reader - const [clStr] = await readString(stream); - return new Values(clStr.toString()); -}; - -JACLPKG.intern('ENABLE-JS-SYNTAX').fvalue = () => { - READTABLE - .val() - .makeDispatchMacroChar('@', true) - .setDispatchMacroChar('@', '"', readJsString) - return null; -}; -JACLPKG.exportSymbol('ENABLE-JS-SYNTAX'); - const isMacroForm = form => { return form instanceof Cons && form.car