author | Alan Dipert
<alan@dipert.org> 2020-08-05 04:12:47 UTC |
committer | Alan Dipert
<alan@dipert.org> 2020-08-05 04:12:47 UTC |
parent | d5b6e651663524db3d00d038b0826c0989704277 |
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');