git » jacl.git » commit 092f439

WIP &key

author Alan Dipert
2019-10-30 13:35:12 UTC
committer Alan Dipert
2019-10-30 13:35:12 UTC
parent a12d9d1758f8df650039e527fe379951bf3b963e

WIP &key

jacl.js +62 -11

diff --git a/jacl.js b/jacl.js
index c7088b9..effedb1 100644
--- a/jacl.js
+++ b/jacl.js
@@ -6,11 +6,22 @@ class Cons {
     this.car = car;
     this.cdr = cdr;
   }
+  static isProperList(cons) {
+    if (cons === null) return true;
+    if (!(cons instanceof Cons)) return false;
+    return Cons.isProperList(cons.cdr);
+  }
   static listOf(...xs) {
     let list = null;
     for(let i = xs.length-1; i >= 0; i--) list = new Cons(xs[i], list);
     return list;
   }
+  static length(cons) {
+    return cons.cdr === null ? 1 : 1 + Cons.length(cons.cdr);
+  }
+  static nth(cons, n) {
+    return n === 0 ? cons.car : Cons.nth(cons.cdr, n-1);
+  }
   static append(...xs) {
     if (xs.length === 0) {
       return null;
@@ -895,27 +906,27 @@ const parseLambdaList = list => {
         } else if (x instanceof LispSymbol) {
           sections.optional.push([x, UNDEFINED, UNDEFINED]);
         } else if (x instanceof Cons) {
-          const opt = Cons.toArray(x);
-          console.log(opt);
-          switch (opt.length) {
+          if (!Cons.isProperList(x))
+            throw new Error(`&OPTIONAL parameter list is improper`);
+          switch (Cons.length(x)) {
             case 0:
               throw new Error(`Empty optional parameter`);
             case 1:
-              if (!(opt[0] instanceof LispSymbol))
+              if (!(x.car instanceof LispSymbol))
                 throw new Error(`Optional parameter name not a symbol`);
-              sections.optional.push([opt[0], UNDEFINED, UNDEFINED]);
+              sections.optional.push([x.car, UNDEFINED, UNDEFINED]);
               break;
             case 2:
-              if (!(opt[0] instanceof LispSymbol))
+              if (!(x.car instanceof LispSymbol))
                 throw new Error(`Optional parameter name not a symbol`);
-              sections.optional.push([opt[0], opt[1], UNDEFINED]);
+              sections.optional.push([x.car, x.cdr.car, UNDEFINED]);
               break;
             case 3: {
-              if (!(opt[0] instanceof LispSymbol))
+              if (!(x.car instanceof LispSymbol))
                 throw new Error(`Optional parameter name not a symbol`);
-              if (!(opt[2] instanceof LispSymbol))
+              if (!(Cons.nth(x, 2) instanceof LispSymbol))
                 throw new Error(`Optional parameter svar not a symbol`);
-              sections.optional.push(opt);
+              sections.optional.push(Cons.toArray(x));
               break;
             }
             default:
@@ -949,6 +960,44 @@ const parseLambdaList = list => {
         }
         break;
       case 'key':
+        if (clSym(x, '&OPTIONAL')) {
+          throw new Error(`Misplaced &OPTIONAL`);
+        } else if (clSym(x, '&KEY')) {
+          throw new Error(`Repeated &KEY`);
+        } else if (clSym(x, '&REST')) {
+          state = 'rest';
+        } else if (x instanceof LispSymbol) {
+          sections.key.push([x, UNDEFINED, UNDEFINED]);
+        } else if (x instanceof Cons) {
+          if (!Cons.isProperList(x))
+            throw new Error(`&OPTIONAL parameter list is improper`);
+          switch (Cons.length(x)) {
+            case 0:
+              throw new Error(`Empty optional parameter`);
+            case 1:
+              if (!(x.car instanceof LispSymbol))
+                throw new Error(`Optional parameter name not a symbol`);
+              sections.optional.push([x.car, UNDEFINED, UNDEFINED]);
+              break;
+            case 2:
+              if (!(x.car instanceof LispSymbol))
+                throw new Error(`Optional parameter name not a symbol`);
+              sections.optional.push([x.car, x.cdr.car, UNDEFINED]);
+              break;
+            case 3: {
+              if (!(x.car instanceof LispSymbol))
+                throw new Error(`Optional parameter name not a symbol`);
+              if (!(Cons.nth(x, 2) instanceof LispSymbol))
+                throw new Error(`Optional parameter svar not a symbol`);
+              sections.optional.push(Cons.toArray(x));
+              break;
+            }
+            default:
+              throw new Error(`Invalid &OPTIONAL spec`);
+          }
+        } else {
+          throw new Error(`Optional argument not symbol or list`);
+        }
         break;
       case 'aux':
         break;
@@ -1445,7 +1494,9 @@ var buf = new BufferedStream(),
     emitNode(sb.append.bind(sb), node);
     const code = sb.toString();
     console.log('generated:', code);
-    console.log('evaled:', eval(code));
+    const evald = eval(code);
+    console.log('evaled:', evald);
+    console.log('parsed', parseLambdaList(evald));
   }
 })()