git » jacl.git » commit 73c9e52

&key: improve &allow-other-keys/:allow-other-keys

author Alan Dipert
2019-11-04 16:26:17 UTC
committer Alan Dipert
2019-11-04 16:26:17 UTC
parent 65381b9f9a5d0017a846b5b346213814df3b5d87

&key: improve &allow-other-keys/:allow-other-keys

jacl.js +19 -9

diff --git a/jacl.js b/jacl.js
index ae7b766..a10b81d 100644
--- a/jacl.js
+++ b/jacl.js
@@ -1368,6 +1368,21 @@ const emitBlock = (print, statements, ret) => {
   }
 };
 
+// Assumes JS variables keyVals and knownKeys have been emitted
+const emitKeyCheck = (print, lambdaList) => {
+  if (!lambdaList.keyAllowOthers) {
+    // If :allow-other-keys passed and non-nil, skip check. Passed keywords
+    // are stored by .name.
+    print(`if(!(keyVals.hasOwnProperty('ALLOW-OTHER-KEYS')&&keyVals['ALLOW-OTHER-KEYS']!==null)){\n`);
+      print('for(var prop in keyVals){\n');
+        print(`if(keyVals.hasOwnProperty(prop)){\n`);
+          print(`if(!knownKeys.includes(prop))throw new Error('Unknown keyword argument: '+prop);\n`);
+        print('}');
+      print('}');
+    print('}\n');
+  }
+};
+
 const emitNode = (print, node) => {
   const { op, env: { context }, parent, form } = node;
   switch (op) {
@@ -1460,6 +1475,8 @@ const emitNode = (print, node) => {
     case 'lambda': {
       print('(function(');
       // Emit required argument names
+      // TODO Move lambda list production to a function for use by macro ll,
+      // destructuring-bind, etc. Similar to emitBlock.
       for (let i = 0; i < node.lambdaList.required.length; i++) {
         print(mungeSym(node.lambdaList.required[i], 'local'))
         if (i < node.lambdaList.required.length-1) print(',');
@@ -1560,15 +1577,8 @@ const emitNode = (print, node) => {
         print(`if(!keyVals.hasOwnProperty(arguments[i].name)){\n`);
         print('keyVals[arguments[i].name]=arguments[i+1];\n');
         print('}}\n');
-        const allowOtherKw = escapeSingle(LispSymbol.kw('ALLOW-OTHER-KEYS', false).name);
-        // Unspecified keys are allowed either by including the keyword 
-        // &allow-other-keys after the &key section or by supplying the keyword
-        // param :allow-other-keys with a logically true value
-        print(`if(!${node.lambdaList.keyAllowOthers}&&!(keyVals.hasOwnProperty('${allowOtherKw}')&&keyVals['${allowOtherKw}']!==null)){\n`);
-        print('for(var prop in keyVals){\n');
-        print(`if(keyVals.hasOwnProperty(prop)){\n`);
-        print(`if(!knownKeys.includes(prop))throw new Error('Unknown keyword argument: '+prop);\n`);
-        print('}}}\n');
+        // Conditionally reject unknown keys
+        emitKeyCheck(print, node.lambdaList);
         for (const kspec of node.lambdaList.key) {
           print(`if(keyVals.hasOwnProperty('${escapeSingle(kspec.key.name)}')){\n`);
           print(mungeSym(kspec.name, 'local'));