git » jacl.git » commit 8b19975

we have %JS; fix %LET bug when bindings empty

author Alan Dipert
2019-10-24 04:33:14 UTC
committer Alan Dipert
2019-10-24 04:33:14 UTC
parent 1a385ccbbb65f6ef1387316e52c6264a54462a2d

we have %JS; fix %LET bug when bindings empty

jacl.js +36 -1

diff --git a/jacl.js b/jacl.js
index 0542de6..d6aaf4a 100644
--- a/jacl.js
+++ b/jacl.js
@@ -27,6 +27,9 @@ class Cons {
       return xs.reduce((a, b) => Cons.append(a,b));
     }
   }
+  static toArray(cons) {
+    return cons ? Array.from(cons) : [];
+  }
   static listStar(...xs) {
     if (xs.length === 0) {
       throw new Error(`LIST* requires at least one argument`);
@@ -906,6 +909,19 @@ const analyzeSpecials = new Map([
     Object.assign(node, analyzeBlock(bodyEnv, node, exprs));
     return node;
   }],
+  [JACLPKG.intern('%JS'), (env, parent, form) => {
+    const [, template, ...args] = form,
+      templateStr = template.toString(),
+      numPlaceholders = (templateStr.match(/~{}/g) || []).length;
+
+    if (numPlaceholders !== args.length)
+      throw new Error(`%JS wrong number of arguments`);
+
+    const node = makeNode('js', { env: env, parent: parent, form: form });
+    node.args = args.map(x => analyze(env.withContext('sval'), node, x));
+    node.template = templateStr;
+    return node;
+  }],
   [JACLPKG.intern('%LET'), (env, parent, form) => {
     const [, bindings, ...body] = form;
     const node = makeNode('let', {
@@ -913,7 +929,7 @@ const analyzeSpecials = new Map([
       parent: parent,
       form: form
     });
-    node.bindings = Array.from(bindings).map(([name, expr]) => {
+    node.bindings = Cons.toArray(bindings).map(([name, expr]) => {
       return [name, analyze(env.withContext('sval'), node, expr)];
     });
     return merge(
@@ -1208,6 +1224,25 @@ const emitNode = (print, node) => {
       emitNode(print, node.val);
       if (context !== 'sval') print(';\n');
       break;
+    case 'js':
+      if (context === 'return') print('return ');
+      if (node.args.length) {
+        let template = node.template,
+          args = [...node.args],
+          end = -1;
+        while (true) {
+          end = template.indexOf('~{}');
+          if (end < 0) break;
+          print(template.substring(0, end));
+          emitNode(print, args.shift());
+          template = template.substring(end+3);
+        }
+        print(template);
+      } else {
+        print(node.template);
+      }
+      if (context !== 'sval') print(';\n');
+      break;
     case 'let':
       if (context === 'sval') print('(function()');
       print('{');