author | Alan Dipert
<alan@dipert.org> 2019-10-17 23:10:12 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-17 23:10:12 UTC |
parent | ddb5e10199d5266f04121d3968f32dc83e1a165d |
jacl.js | +76 | -50 |
diff --git a/jacl.js b/jacl.js index 8d20ee3..b00299f 100644 --- a/jacl.js +++ b/jacl.js @@ -10,18 +10,21 @@ class Cons { for(let i = xs.length-1; i >= 0; i--) list = new Cons(xs[i], list); return list; } - append(...xs) { + static append(...xs) { if (xs.length === 0) { - return this; - } else if (xs.length === 1 && !(xs[0] instanceof Cons)) { - const copy = Cons.listOf(...this); + return null; + } else if (xs.length === 1) { + return xs[0]; + } else if (xs.length === 2 && !(xs[1] instanceof Cons)) { + const copy = Cons.listOf(...xs[0]); let last = copy; while (last.cdr) last = last.cdr; - last.cdr = xs[0]; + last.cdr = xs[1]; return copy; + } else if (xs.length === 2) { + return Cons.listOf(...xs[0], ...xs[1]); } else { - const [x, ...more] = xs; - return Cons.listOf(...this, ...x).append(...more); + return xs.reduce((a, b) => Cons.append(a,b)); } } [Symbol.iterator]() { @@ -704,50 +707,74 @@ JACLPKG.intern('UNQUOTE').setMacro().fvalue = function(env, form) { throw new Error(`Comma not inside backquote`); }; -JACLPKG.intern('QUASIQUOTE').setMacro().fvalue = function(env, form) { - const transform = (form, wrapInList = true) => { - const maybeWrap = x => wrapInList ? Cons.listOf(x) : x; - if (form instanceof Cons && JACLPKG.intern('UNQUOTE') === form.car) { - return maybeWrap(form.cdr.car); - } else if (form instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === form.car) { - return form.cdr.car; - } else { - return maybeWrap(transformQuasiquoteArgument(form)); - } - }; - const transformCompound = compound => { - const rec = object => { - if (object instanceof Cons && (!(object.car instanceof Cons) || JACLPKG.intern('UNQUOTE') === object.car)) { - return Cons.listOf(transform(object.car), transform(object.cdr, false)); - } else if (object instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === object.car) { - throw new Error(`UNQUOTE-SPLICING in dotted list`); - } else { - return new Cons(transform(object.car), rec(object.cdr)); - } - }; - return rec(compound); - }; - const transformQuasiquoteArgument = argument => { - if (argument instanceof Cons && JACLPKG.intern('UNQUOTE') === argument.car) { - return argument.cdr.car; - } else if (argument instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === argument.car) { - throw new Error(`UNQUOTE-SPLICING at top`); - } else if (argument instanceof Cons) { - console.log(argument); - const out = Cons.listOf( + +const transform = (form, wrapInList = true) => { + const maybeWrap = x => { + if (wrapInList) { + return Cons.listOf( JACLPKG.intern('%CALL'), Cons.listOf( JACLPKG.intern('%DOT'), JSPKG.intern('Cons'), - new LispSymbol('append', null) - ) - ).append(transformCompound(argument)); - console.log(out); - throw new Error('omg'); + new LispSymbol('listOf', null) + ), + x + ); + } else { + return x; + } + } + if (form instanceof Cons && JACLPKG.intern('UNQUOTE') === form.car) { + return maybeWrap(form.cdr.car); + } else if (form instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === form.car) { + return form.cdr.car; + } else { + return maybeWrap(transformQuasiquoteArgument(form)); + } +}; +const transformCompound = compound => { + const rec = object => { + if (object instanceof Cons && JACLPKG.intern('UNQUOTE') === object.car) { + return Cons.listOf(transform(object.car), transform(object.cdr, false)); + } else if (object instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === object.car) { + throw new Error(`UNQUOTE-SPLICING in dotted list`); + } else if (object === null) { + return null; } else { - return Cons.listOf(CLPKG.intern('QUOTE'), argument); + return new Cons(transform(object.car), rec(object.cdr)); } }; + return rec(compound); +}; + +const ppr = x => { + if (x instanceof Cons) { + return Array.from(x).map(ppr); + } else if (x instanceof LispSymbol) { + return x.name; + } else { + return x.toString(); + } +}; + +const transformQuasiquoteArgument = argument => { + if (argument instanceof Cons && JACLPKG.intern('UNQUOTE') === argument.car) { + return argument.cdr.car; + } else if (argument instanceof Cons && JACLPKG.intern('UNQUOTE-SPLICING') === argument.car) { + throw new Error(`UNQUOTE-SPLICING at top`); + } else if (argument instanceof Cons) { + const foo = Cons.listOf( + JACLPKG.intern('%CALL'), + Cons.listOf(JACLPKG.intern('%DOT'), JSPKG.intern('Cons'), new LispSymbol('append', null)), + ...transformCompound(argument) + ); + return foo; + } else { + return Cons.listOf(CLPKG.intern('QUOTE'), argument); + } +}; + +JACLPKG.intern('QUASIQUOTE').setMacro().fvalue = function(env, form) { const expand = form => { if (form instanceof Cons) { const expanded = new Cons(expand(form.car), expand(form.cdr)); @@ -956,7 +983,6 @@ const analyzeList = (env, parent, form) => { } else if (isLambdaForm(form.car) || form.car instanceof LispSymbol) { return parseCall(env, parent, form); } else { - console.log('call', form); throw new Error(`Invalid call`) } }; @@ -1131,11 +1157,11 @@ var buf = new BufferedStream(), console.log("read:", obj); const node = analyze(emptyEnv, null, obj); console.log("analyzed:", node); - //const sb = new StringBuffer(); - //emitNode(sb.append.bind(sb), node); - //const code = sb.toString(); - //console.log("generated:", code); - //console.log("evaled:", eval(code)); + const sb = new StringBuffer(); + emitNode(sb.append.bind(sb), node); + const code = sb.toString(); + console.log("generated:", code); + console.log("evaled:", eval(code)); } })()