author | Alan Dipert
<alan@dipert.org> 2019-11-04 16:26:17 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-11-04 16:26:17 UTC |
parent | 65381b9f9a5d0017a846b5b346213814df3b5d87 |
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'));