git » jacl.git » commit 1656bb3

%lambda analysis wip

author Alan Dipert
2019-10-31 13:03:32 UTC
committer Alan Dipert
2019-10-31 13:03:32 UTC
parent 6d3ab08b7ee1b46ec898e61a3f5d320a35027a83

%lambda analysis wip

jacl.js +36 -50

diff --git a/jacl.js b/jacl.js
index e0a377a..2dee0c7 100644
--- a/jacl.js
+++ b/jacl.js
@@ -1000,15 +1000,27 @@ const parseLambdaList = list => {
   return sections;
 };
 
-const analyzeLambdaList = (env, parent, sections) => {
-  // https://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node64.html
-  // Whenever any initform is evaluated for any parameter specifier, that form
-  // may refer to any parameter variable to the left of the specifier in which
-  // the initform appears, including any supplied-p variables, and may rely on
-  // the fact that no other parameter variable has yet been bound (including
-  // its own parameter variable). 
-  // TODO Thread env through names/initforms and return a new `sections` with
-  // every initform replaced with its analysis
+const analyzeLambdaList = (env, parent, list) => {
+  const sections = parseLambdaList(list);
+  env = env.withLocals(sections.required);
+  for (let i = 0; i < sections.optional.length; i++) {
+    const spec = sections.optional[i];
+    if (spec.initform !== UNDEFINED) {
+      spec.initform = analyze(env, parent, spec.initform);
+    }
+    env = env.withLocals([spec.name]);
+    if (spec.svar !== UNDEFINED) {
+      env = env.withLocals([spec.svar]);
+    }
+  }
+  // TODO:
+  // rest
+  // key
+  // aux
+  return {
+    lambdaList: sections,
+    bodyEnv: env
+  };
 };
 
 const stringy = x => x instanceof String || typeof x === 'string' || x instanceof LispString;
@@ -1040,38 +1052,15 @@ const analyzeSpecials = new Map([
     node.args = args.map(analyze.bind(null, env.withContext('sval'), node))
     return node;
   }],
-  // TODO majorly broken because of Env overhaul
   [JACLPKG.intern('%LAMBDA'), (env, parent, form) => {
-    const [, arglist, ...exprs] = form,
-          args                  = (arglist === null ? [] : Array.from(arglist))
-                                    .map(x => {
-                                      if (!(x instanceof LispSymbol))
-                                        throw new Error(`Args must be symbols`);
-                                      return x.name;
-                                    }),
-          restIdx               = args.findIndex(x => x === '&REST'),
-          isVariadic            = restIdx >= 0,
-          argNames              = args.filter(x => x !== '&REST');
-
-    if (isVariadic && restIdx != args.length-2) {
-      throw new Error(`&REST must be followed by argument symbol`);
-    }
-
-    // TODO locals are now stored as syms
-    const bodyEnv = env.withContext('return').withLocals(argNames);
-    argNames.forEach(s => bodyEnv.localVals.add(s));
-
-    const node = makeNode('lambda', {
-        env: env,
-        parent: parent,
-        form: form,
-        isVariadic: isVariadic,
-        restArgName: isVariadic ? args[restIdx+1] : null,
-        minArgs: argNames.length - (isVariadic ? 1 : 0),
-        argNames: argNames,
-      });
-    Object.assign(node, analyzeBlock(bodyEnv, node, exprs));
-    return node;
+    const [, list, ...body] = form;
+    const node = makeNode('lambda', { env: env, parent: parent, form: form });
+    const { lambdaList, bodyEnv } = analyzeLambdaList(env, node, list);
+    node.lambdaList = lambdaList;
+    return merge(
+      node,
+      analyzeBlock(bodyEnv, node, body)
+    );
   }],
   [JACLPKG.intern('%JS'), (env, parent, form) => {
     const [, template, ...args] = form,
@@ -1245,9 +1234,6 @@ const analyzeSymbol = (env, parent, form) => {
   return node;
 };
 
-// TODO Use env strategy where we synthesize local names so that we can guarantee
-// they are deconflicted with locals generated by compiler for impl. of e.g.
-// TAGBODY. For interop, provide js::WINDOW instead of arbitrary JS name access
 class Env {
   constructor(init = true) {
     if (init) Env.init(this);
@@ -1495,13 +1481,13 @@ var buf = new BufferedStream(),
     console.log('read:', obj);
     const node = analyze(emptyEnv, null, obj);
     console.log('analyzed:', node);
-    const sb = new StringBuffer();
-    emitNode(sb.append.bind(sb), node);
-    const code = sb.toString();
-    console.log('generated:', code);
-    const evald = eval(code);
-    console.log('evaled:', evald);
-    console.log('parsed', parseLambdaList(evald));
+    //const sb = new StringBuffer();
+    //emitNode(sb.append.bind(sb), node);
+    //const code = sb.toString();
+    //console.log('generated:', code);
+    //const evald = eval(code);
+    //console.log('evaled:', evald);
+    //console.log('parsed', parseLambdaList(evald));
   }
 })()