author | Alan Dipert
<alan@dipert.org> 2019-10-19 04:08:13 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-19 04:08:13 UTC |
parent | 4aff94cbeb4f936a50c75efb0ceaeffb38484645 |
jacl.js | +61 | -12 |
diff --git a/jacl.js b/jacl.js index d89cbd7..61f6122 100644 --- a/jacl.js +++ b/jacl.js @@ -899,11 +899,10 @@ const analyzeSpecials = new Map([ if (!(target instanceof LispSymbol)) throw new Error(`Can't assign to non-symbol`); if (target.isConstant) - throw new Erorr(`Can't set constant`); + throw new Error(`Can't set constant`); - const svalEnv = env.withContext("sval"); - const targetExpr = analyze(svalEnv, null, target); - const valExpr = analyze(svalEnv, null, val); + const targetExpr = analyze(env.withContext("lval"), null, target); + const valExpr = analyze(env.withContext("sval"), null, val); const node = makeNode("set", { env: env, @@ -966,6 +965,24 @@ const analyzeSpecials = new Map([ form: form, tagName: tagName }); + }], + [JACLPKG.intern("%IF"), (env, parent, form) => { + if ([...form].length < 4) throw new Error(`IF requires at least 3 args`); + const [, pred, expr0, expr1] = form; + const testNode = analyze(env.withContext("sval"), null, pred), + thenNode = analyze(env, null, expr0), + elseNode = analyze(env, null, expr1); + const node = makeNode("if", { + env: env, + parent: parent, + form: form, + testNode: testNode, + thenNode: thenNode, + elseNode: elseNode + }); + + testNode.parent = thenNode.parent = elseNode.parent = node; + return node; }] ]); @@ -1081,6 +1098,8 @@ const constantCode = val => { } }; +const truth = x => x != null && x !== false; + const emitNode = (print, node) => { const { op, env: { context }, parent, form } = node; switch (op) { @@ -1108,19 +1127,28 @@ const emitNode = (print, node) => { case "local": if (context === "return") print("return "); print(munge(form.name)); - if (context !== "sval") print(";\n"); + if (context !== "sval" && context !== "lval") print(";\n"); break; case "global": + // TODO revisit the sanity of the 'lval' concept for %SET if (context === "return") print("return "); - print(`Package.get('${escapeSingle(form.packageName)}', true).intern('${escapeSingle(form.name)}')`); - if (node.slot === 'value') { - print(".val()"); - } else if (node.slot === 'function') { - print(".func()"); + if (form.packageName === 'COMMON-LISP' && form.name === 'NIL') { + print("null"); } else { - throw new Error(`Unknown global slot: ${node.slot}`); + print(`Package.get('${escapeSingle(form.packageName)}', true).intern('${escapeSingle(form.name)}')`); + if (node.slot === 'value') { + if (context === 'lval') { + print(".value"); + } else { + print(".val()"); + } + } else if (node.slot === 'function') { + print(".func()"); + } else { + throw new Error(`Unknown global slot: ${node.slot}`); + } } - if (context !== "sval") print(";\n"); + if (context !== "sval" && context !== "lval") print(";\n"); break; case "set": if (context === "return") print("return "); @@ -1140,6 +1168,27 @@ const emitNode = (print, node) => { print(")"); if (context !== "sval") print(";\n"); break; + case "if": + console.log(node); + if (context === "sval" || context === "return") { + print("(truth("); + emitNode(print, node.testNode); + print(")?") + emitNode(print, node.thenNode); + print(":"); + emitNode(print, node.elseNode); + print(")"); + } else { + print("if("); + emitNode(print, node.testNode); + print(")\n\t"); + emitNode(print, node.thenNode); + print("else\n\t"); + emitNode(print, node.elseNode); + print("\n"); + } + break; + // TODO if // TODO tagbody // TODO lambda