git » jacl.git » commit 30af31b

finish %set and %if

author Alan Dipert
2019-10-19 04:08:13 UTC
committer Alan Dipert
2019-10-19 04:08:13 UTC
parent 4aff94cbeb4f936a50c75efb0ceaeffb38484645

finish %set and %if

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