git » jacl.git » commit 4983d9a

Fix egregious lexenv but. Will need to port to flocals

author Alan Dipert
2020-08-05 04:12:47 UTC
committer Alan Dipert
2020-08-05 04:12:47 UTC
parent d5b6e651663524db3d00d038b0826c0989704277

Fix egregious lexenv but. Will need to port to flocals

jacl.js +56 -41

diff --git a/jacl.js b/jacl.js
index 83e02b6..cb12ab7 100644
--- a/jacl.js
+++ b/jacl.js
@@ -1268,48 +1268,50 @@ const parseLambdaList = (list, isMacro) => {
 };
 
 const analyzeLambdaList = (env, parent, list, isMacro) => {
-  const sections = parseLambdaList(list, isMacro);
-  env = env.withLocals(sections.required);
+  const sections = parseLambdaList(list, isMacro),
+        locals = [...sections.required],
+        envId = env.counter();
   const initforms = [];
   for (const spec of sections.optional) {
     if (spec.initform !== UNDEFINED) {
-      spec.initform = analyze(env, parent, spec.initform);
+      spec.initform = analyze(env.withLocals(locals, envId), parent, spec.initform);
       initforms.push(spec.initform)
     }
-    env = env.withLocals([spec.name]);
+    locals.push(spec.name);
     if (spec.svar !== UNDEFINED) {
-      env = env.withLocals([spec.svar]);
+      locals.push(spec.svar);
     }
   }
   if (sections.rest)
-    env = env.withLocals([sections.rest])
+    locals.push(sections.rest);
   if (sections.body)
-    env = env.withLocals([sections.body])
+    locals.push(sections.body);
   if (sections.environment)
-    env = env.withLocals([sections.environment])
+    locals.push(sections.environment);
   if (sections.whole)
-    env = env.withLocals([sections.whole])
+    locals.push(sections.whole);
   for (const spec of sections.key) {
     if (spec.initform !== UNDEFINED) {
-      spec.initform = analyze(env, parent, spec.initform);
+      spec.initform = analyze(env.withLocals(locals, envId), parent, spec.initform);
       initforms.push(spec.initform)
     }
-    env = env.withLocals([spec.name]);
+    locals.push(spec.name);
     if (spec.svar !== UNDEFINED) {
-      env = env.withLocals([spec.svar]);
+      locals.push(spec.svar);
     }
   }
   for (const spec of sections.aux) {
     if (spec.initform !== UNDEFINED) {
-      spec.initform = analyze(env, parent, spec.initform);
+      spec.initform = analyze(env.withLocals(locals, envId), parent, spec.initform);
       initforms.push(spec.initform)
     }
-    env = env.withLocals([spec.name]);
+    locals.push(spec.name);
   }
   return {
     lambdaList: sections,
     initforms: initforms,
-    bodyEnv: env
+    bodyEnv: env.withLocals(locals, envId),
+    envId: envId
   };
 };
 
@@ -1369,11 +1371,12 @@ const analyzeSpecials = new Map([
       declarations: declarations,
       isMacro: isMacro
     });
-    const { lambdaList, initforms, bodyEnv } = analyzeLambdaList(
+    const { lambdaList, initforms, bodyEnv, envId } = analyzeLambdaList(
       env.withContext('expr'), node, list, isMacro
     );
     node.lambdaList = lambdaList;
     node = merge(node, analyzeBlock(bodyEnv, node, body));
+    node.envId = envId;
     node.children = [...node.children, ...initforms];
     return node;
   }],
@@ -1414,6 +1417,7 @@ const analyzeSpecials = new Map([
       form: form
     });
     node.locals = [];
+    node.envId = env.counter();
     node.specials = [];
     for (const binding of List.toArray(bindings)) {
       if (!List.isProperList(binding) || List.length(binding) !== 2)
@@ -1429,7 +1433,7 @@ const analyzeSpecials = new Map([
     return merge(
       node,
       analyzeBlock(
-        env.withLocals(node.locals.map(([name]) => name)),
+        env.withLocals(node.locals.map(([name]) => name), node.envId),
         node,
         body
       )
@@ -1451,7 +1455,7 @@ const analyzeSpecials = new Map([
 
     const valExpr = analyze(env.withContext('expr'), null, val);
 
-    let op;
+    let op, envId;
 
     if (env.hasLocal(target)) {
       // Local
@@ -1463,6 +1467,9 @@ const analyzeSpecials = new Map([
     }
 
     const node = makeNode(op, { env: env, parent: parent, form: form });
+    if (op === 'set-local') {
+      node.envId = env.localEnvId(target);
+    }
     node.targetSym = target;
     node.val = valExpr;
     node.val.parent = node;
@@ -1615,6 +1622,7 @@ const analyzeSymbol = (env, parent, form) => {
     node.name = form.name;
   } else if (env.hasLocal(form)) {
     node.op = 'local';
+    node.envId = env.localEnvId(form);
   } else {
     node.op = 'global';
     node.slot = 'value';
@@ -1634,7 +1642,8 @@ class Env {
     return this;
   }
   static init(env) {
-    env.locals = new Set();
+    // sym => envId
+    env.locals = new Map();
     env.localFunctions = new Set();
     // sym => tagbodyName
     env.tags = new Map();
@@ -1644,16 +1653,19 @@ class Env {
   }
   clone() {
     const newEnv = new Env(false);
-    newEnv.locals = new Set(this.locals);
+    newEnv.locals = new Map(this.locals);
     newEnv.localFunctions = new Set(this.localFunctions);
     newEnv.tags = new Map(this.tags);
     newEnv.context = this.context;
     newEnv.counter = this.counter;
     return newEnv;
   }
-  withLocals(syms) {
+  withLocals(syms, envId = this.counter()) {
     const newEnv = this.clone();
-    newEnv.locals = new Set([...this.locals, ...syms]);
+    newEnv.locals = new Map([
+      ...this.locals,
+      ...syms.map(sym => [sym, envId])
+    ]);
     return newEnv;
   }
   withLocalFunctions(syms) {
@@ -1672,6 +1684,9 @@ class Env {
     ]);
     return newEnv;
   }
+  localEnvId(sym) {
+    return this.locals.get(sym);
+  }
   hasLocal(sym) {
     return this.locals.has(sym);
   }
@@ -1850,7 +1865,7 @@ const emitNode = (print, node) => {
       break;
     case 'local':
       if (context === 'return') print('return ');
-      print(mungeSym(form, 'local'));
+      print(mungeSym(form, `local_${node.envId}`));
       if (context !== 'expr') print(';\n');
       break;
     case 'flocal':
@@ -1883,7 +1898,7 @@ const emitNode = (print, node) => {
       break;
     case 'set-local':
       if (context === 'return') print('return ');
-      print(mungeSym(node.targetSym, 'local'))
+      print(mungeSym(node.targetSym, `local_${node.envId}`))
       print('=');
       emitNode(print, node.val);
       if (context !== 'expr') print(';\n');
@@ -1936,7 +1951,7 @@ const emitNode = (print, node) => {
       if (node.locals.length) print('var ');
       for (let i = 0; i < node.locals.length; i++) {
         const [ name, val ] = node.locals[i];
-        print(mungeSym(name, 'local'));
+        print(mungeSym(name, `local_${node.envId}`));
         print('=');
         emitNode(print, val);
         if (i < node.locals.length-1) print(',');
@@ -1970,14 +1985,14 @@ const emitNode = (print, node) => {
         JACLPKG.intern('&WHOLE')
       ].concat(node.lambdaList.required) : node.lambdaList.required;
       for (let i = 0; i < required.length; i++) {
-        print(mungeSym(required[i], 'local'))
+        print(mungeSym(required[i], `local_${node.envId}`))
         if (i < required.length-1) print(',');
       }
       // Emit optional argument names
       if (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'))
+        print(mungeSym(node.lambdaList.optional[i].name, `local_${node.envId}`))
         if (i < node.lambdaList.optional.length-1) print(',');
       }
       print('){\n');
@@ -1998,10 +2013,10 @@ const emitNode = (print, node) => {
       // Macro-specific and conditional assignment of &ENVIRONMENT and &WHOLE
       if (node.isMacro) {
         if (node.lambdaList.environment) {
-          print(`var ${mungeSym(node.lambdaList.environment, 'local')} = ${mungeSym(required[0], 'local')};\n`);
+          print(`var ${mungeSym(node.lambdaList.environment, 'local_${node.envId}')} = ${mungeSym(required[0], 'local_${node.envId}')};\n`);
         }
         if (node.lambdaList.whole) {
-          print(`var ${mungeSym(node.lambdaList.whole, 'local')} = ${mungeSym(required[1], 'local')};\n`);
+          print(`var ${mungeSym(node.lambdaList.whole, 'local_${node.envId}')} = ${mungeSym(required[1], 'local_${node.envId}')};\n`);
         }
       }
       // &optional
@@ -2010,7 +2025,7 @@ const emitNode = (print, node) => {
           print('var ');
           for (let i = 0; i < node.lambdaList.optionalSvars.length; i++) {
             const svar = node.lambdaList.optionalSvars[i];
-            print(mungeSym(svar, 'local'));
+            print(mungeSym(svar, `local_${node.envId}`));
             print('=true');
             if (i < node.lambdaList.optionalSvars.length-1) print(',');
           }
@@ -2020,7 +2035,7 @@ const emitNode = (print, node) => {
         for (let i = 0; i < node.lambdaList.optional.length; i++) {
           const ospec = node.lambdaList.optional[i];
           print(`case ${min+i}:\n`);
-          print(mungeSym(ospec.name, 'local'));
+          print(mungeSym(ospec.name, `local_${node.envId}`));
           print('=');
           if (ospec.initform === UNDEFINED) {
             print('null');
@@ -2029,8 +2044,8 @@ const emitNode = (print, node) => {
           }
           print(';\n');
           if (ospec.svar !== UNDEFINED) {
-            print(mungeSym(ospec.svar, 'local'));
-            print('=false;\n');
+            print(mungeSym(ospec.svar, `local_${node.envId}`));
+            print('=null;\n');
           }
         }
         print('default:\n');
@@ -2041,9 +2056,9 @@ const emitNode = (print, node) => {
       const restStart = required.length
         + node.lambdaList.optional.length;
       if (node.lambdaList.rest) {
-        print(mungeSym(node.lambdaList.rest, 'local'));
+        print(mungeSym(node.lambdaList.rest, `local_${node.envId}`));
       } else if (node.lambdaList.body) {
-        print(mungeSym(node.lambdaList.body, 'local'));
+        print(mungeSym(node.lambdaList.body, `local_${node.envId}`));
       }
       if (node.lambdaList.rest || node.lambdaList.body) {
         print('=');
@@ -2058,7 +2073,7 @@ const emitNode = (print, node) => {
         if (node.lambdaList.keySvars.length) {
           print('var ');
           for (let i = 0; i < node.lambdaList.keySvars.length; i++) {
-            print(mungeSym(node.lambdaList.keySvars[i], 'local'));
+            print(mungeSym(node.lambdaList.keySvars[i], `local_${node.envId}`));
             print('=true');
             if (i < node.lambdaList.keySvars.length-1) print(',');
           }
@@ -2066,7 +2081,7 @@ const emitNode = (print, node) => {
         }
         print('var ');
         for (let i = 0; i < node.lambdaList.key.length; i++) {
-          print(mungeSym(node.lambdaList.key[i].name, 'local'));
+          print(mungeSym(node.lambdaList.key[i].name, `local_${node.envId}`));
           print('=null')
           if (i < node.lambdaList.key.length-1) print(',');
         }
@@ -2086,16 +2101,16 @@ const emitNode = (print, node) => {
         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'));
+          print(mungeSym(kspec.name, `local_${node.envId}`));
           print(`=keyVals['${escapeSingle(kspec.key.name)}'];\n`);
           if (kspec.initform !== UNDEFINED) {
             print('}else{\n');
-            print(mungeSym(kspec.name, 'local'));
+            print(mungeSym(kspec.name, `local_${node.envId}`));
             print('=');
             emitNode(print, kspec.initform);
             print(';\n');
             if (kspec.svar !== UNDEFINED) {
-              print(mungeSym(kspec.svar, 'local'));
+              print(mungeSym(kspec.svar, `local_${node.envId}`));
               print('=false;\n');
             }
           }
@@ -2106,7 +2121,7 @@ const emitNode = (print, node) => {
         print('var ');
         for (let i = 0; i < node.lambdaList.aux.length; i++) {
           aspec = node.lambdaList.aux[i];
-          print(mungeSym(aspec.name, 'local'));
+          print(mungeSym(aspec.name, `local_${node.envId}`));
           print('=');
           if (aspec.initform === UNDEFINED) {
             print('null');