author | Alan Dipert
<alan@dipert.org> 2019-10-31 13:03:32 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-31 13:03:32 UTC |
parent | 6d3ab08b7ee1b46ec898e61a3f5d320a35027a83 |
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)); } })()