git » jacl.git » commit c2a3f83

initial populate &optional svars to true

author Alan Dipert
2019-11-03 16:28:22 UTC
committer Alan Dipert
2019-11-03 16:28:22 UTC
parent 35eb9620bcb80fa7daed726c851c8012f3dc69b7

initial populate &optional svars to true

jacl.js +40 -14

diff --git a/jacl.js b/jacl.js
index af46f4f..2b8c4cc 100644
--- a/jacl.js
+++ b/jacl.js
@@ -878,10 +878,17 @@ const parseLambdaList = list => {
 
   let arr = Cons.toArray(list),
     sections = {
+      // Array of symbols
       required: [],
+      // Array of [symbol, expr, symbol] for [name, init, svar]
       optional: [],
+      // Array of optional indexes that have svars
+      optionalWithSvars: [],
+      // null or symbol
       rest: null,
+      // Array of [keyword, symbol, expr, symbol] for [key, name, init, svar]
       key: [],
+      // Array of [symbol, expr] for [name, init]
       aux: []
     },
     state = 'required';
@@ -918,10 +925,15 @@ const parseLambdaList = list => {
           const len = Cons.length(x);
           if (len === 0 || len > 3) 
             throw new Error(`&OPTIONAL parameter list wrong size`);
+          let svar = UNDEFINED;
+          if (len === 3) {
+            svar = checkValidLocal(Cons.nth(x, 2));
+            sections.optionalWithSvars.push(sections.optional.length);
+          }
           sections.optional.push({
             name: checkValidLocal(x.car),
             initform: len > 1 ? Cons.nth(x, 1) : UNDEFINED,
-            svar: len === 3 ? checkValidLocal(Cons.nth(x, 2)) : UNDEFINED
+            svar: svar
           });
         } else {
           throw new Error(`&OPTIONAL parameter not symbol or valid list`);
@@ -1419,32 +1431,46 @@ const emitNode = (print, node) => {
       if (context === 'sval') print(')()');
       break;
     case 'lambda': {
-      // Emit argument names
       print('(function(');
-      print([
-        ...node.lambdaList.required,
-        ...node.lambdaList.optional.map(o => o.name)
-      ].map(s => mungeSym(s, 'local')).join(','));
+      // Emit required argument names
+      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(',');
+      }
+      // Emit optional argument names
+      if (node.lambdaList.required.length && node.lambdaList.optional.length)
+        print(',');
+      for (let i = 0; i < node.lambdaList.optional.length; i++) {
+        print(mungeSym(node.lambdaList.optional[i].name, 'local'))
+        if (i < node.lambdaList.optional.length-1) print(',');
+      }
       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) {
+      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) {
+        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`);
         }
       }
-
-      // TODO bind optional svars all to true
-      // TODO populate optionals, svars depending on arg length
-
+      // Speculatively bind &optional svars to true
+      if (node.lambdaList.optionalWithSvars.length) {
+        print('var ');
+        for (let i = 0; i < node.lambdaList.optionalWithSvars.length; i++) {
+          const optIdx = node.lambdaList.optionalWithSvars[i],
+            ospec = node.lambdaList.optional[optIdx];
+          print(mungeSym(ospec.svar, 'local'));
+          print('=true');
+          if (i < node.lambdaList.optionalWithSvars.length-1) print(',');
+        }
+        print(';\n');
+      }
+      // TODO Initialize &optionals and set svars depending on arg len
       emitBlock(print, node.statements, node.ret);
       print('})');
       break;