git » jacl.git » commit 35eb962

WIP %lambda

author Alan Dipert
2019-11-03 13:44:44 UTC
committer Alan Dipert
2019-11-03 13:44:44 UTC
parent cb4a4d7fac1a48bb9eb0ad9f5dbe65a022316478

WIP %lambda

jacl.js +27 -12

diff --git a/jacl.js b/jacl.js
index e36c048..af46f4f 100644
--- a/jacl.js
+++ b/jacl.js
@@ -1418,22 +1418,37 @@ const emitNode = (print, node) => {
       print('}');
       if (context === 'sval') print(')()');
       break;
-    case 'lambda':
-      print('(function(){\n');
-      // TODO enhance arg length check
-      print(`if(arguments.length!==${node.lambdaList.required.length})throw new Error("Invalid number of arguments: "+arguments.length);\n`);
-      let argidx = 0;
-      if (node.lambdaList.required.length) print('var ');
-      for (let i = 0; i < node.lambdaList.required.length; i++) {
-        print(mungeSym(node.lambdaList.required[i], 'local'));
-        print(`=arguments[${argidx++}]`);
-        if (i < node.lambdaList.required.length-1) print(',');
+    case 'lambda': {
+      // Emit argument names
+      print('(function(');
+      print([
+        ...node.lambdaList.required,
+        ...node.lambdaList.optional.map(o => o.name)
+      ].map(s => mungeSym(s, 'local')).join(','));
+      print('){\n');
+
+      // Emit argument length checks
+      const min = node.lambdaList.required.length,
+        max = node.lambdaList.rest ? false : min + node.lambdaList.optional.length;
+
+      if (min > 0 && min === max) {
+        print(`if (arguments.length !== ${min}) throw new Error('Called with invalid number of arguments: ' + arguments.length);\n`);
+      } else {
+        if (min > 0) {
+          print(`if (arguments.length < ${min}) throw new Error('Called with too few arguments: ' + arguments.length);\n`);
+        }
+        if (max) {
+          print(`if (arguments.length > ${max}) throw new Error('Called with too many arguments: ' + arguments.length);\n`);
+        }
       }
-      if (node.lambdaList.required.length) print(';');
+
+      // TODO bind optional svars all to true
+      // TODO populate optionals, svars depending on arg length
+
       emitBlock(print, node.statements, node.ret);
       print('})');
       break;
-    case 'call':
+    } case 'call':
       if (context === 'return') print('return ');
       emitNode(print, node.f);
       print('(');