author | Alan Dipert
<alan@dipert.org> 2019-10-23 15:04:27 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-23 15:04:27 UTC |
parent | cc7d304763bc04bdff4d8612ae119ca732edb96b |
jacl.js | +55 | -14 |
diff --git a/jacl.js b/jacl.js index cc33b44..0542de6 100644 --- a/jacl.js +++ b/jacl.js @@ -291,6 +291,8 @@ const CLPKG = Package.makePackage('COMMON-LISP', 'CL'); Package.makePackage('COMMON-LISP-USER', 'CL-USER'); Package.makePackage('KEYWORD'); +JACLPKG.intern('!LOG').fvalue = console.log; + // CL package constants // TODO update this, look into constants const CLCONSTS = new Map([ @@ -617,6 +619,15 @@ const munge = s => { return munged; }; +const mungeSym = (sym, prefix = '') => { + prefix = prefix !== '' ? (prefix + '_') : ''; + if (PACKAGE.val().name === sym.packageName) { + return prefix + munge(sym.name); + } else { + return prefix + munge(sym.packageName) + '$' + munge(sym.name); + } +}; + class Token { constructor(initial = '') { this.str = initial; @@ -822,7 +833,7 @@ const analyzeBlock = (env, parent, forms) => { .map(x => analyze(env.withContext('statement'), parent, x)), ret; if (forms.length <= 1) { - ret = analyze(env, parent, forms[0]); + ret = analyze(env.withContext(env.context === 'statement' ? 'statement' : 'return'), parent, forms[0]); } else { ret = analyze( env.withContext(env.context === 'statement' ? 'statement' : 'return'), @@ -856,11 +867,10 @@ const analyzeSpecials = new Map([ return node; }], [JACLPKG.intern('%CALL'), (env, parent, form) => { - env = env.withContext('sval'); const [, func, ...args] = form; const node = makeNode('call', { env: env, parent: parent, form: form }); - node.f = analyze(env, node, func); - node.args = args.map(analyze.bind(null, env, node)) + node.f = analyze(env.withContext('sval'), node, func); + node.args = args.map(analyze.bind(null, env.withContext('sval'), node)) return node; }], // TODO majorly broken because of Env overhaul @@ -898,7 +908,7 @@ const analyzeSpecials = new Map([ }], [JACLPKG.intern('%LET'), (env, parent, form) => { const [, bindings, ...body] = form; - const node = makeNode('let', { + const node = makeNode('let', { env: env, parent: parent, form: form @@ -932,7 +942,7 @@ const analyzeSpecials = new Map([ const node = makeNode(op, { env: env, parent: parent, form: form }); node.targetSym = target; node.val = valExpr; - node.targetSym.parent = node; + node.val.parent = node; return node; }], @@ -1010,11 +1020,14 @@ const parseCall = (env, parent, form) => { let node = makeNode('call', { env: env, parent: parent, form: form }); node.args = args.map(analyze.bind(null, env.withContext('sval'), node)); if (isLambdaForm(func)) { - node.f = analyze(env, parent, func); - } else if (func instanceof LispSymbol && env.localFuns.has(func.name)) { - node.f = makeNode('local', { env: env, parent: node, form: func }); + node.f = analyze(env.withContext('sval'), parent, func); } else if (func instanceof LispSymbol) { - node.f = makeNode('global', { env: env, parent: node, form: func, slot: 'function' }); + node.f = makeNode('global', { + env: env.withContext('sval'), + parent: node, + form: func, + slot: 'function' + }); } return node; }; @@ -1074,7 +1087,6 @@ class Env { withLocals(syms) { const newEnv = this.clone(); newEnv.locals = new Set([...this.locals, ...syms]); - console.log(newEnv.locals); return newEnv; } hasLocal(sym) { @@ -1124,6 +1136,19 @@ const constantCode = val => { const truth = x => x != null && x !== false; +const emitBlock = (print, statements, ret) => { + if (statements.length) { + for (const stmt of statements) { + print('\t'); + emitNode(print, stmt); + } + print('\t'); + emitNode(print, ret); + } else { + emitNode(print, ret); + } +}; + const emitNode = (print, node) => { const { op, env: { context }, parent, form } = node; switch (op) { @@ -1150,7 +1175,7 @@ const emitNode = (print, node) => { break; case 'local': if (context === 'return') print('return '); - print(munge(form.name)); + print(mungeSym(form, 'local')); if (context !== 'sval') print(';\n'); break; case 'global': @@ -1176,13 +1201,29 @@ const emitNode = (print, node) => { if (context !== 'sval') print(';\n'); break; break; - case 'set': + case 'set-local': if (context === 'return') print('return '); - emitNode(print, node.target); + print(mungeSym(node.targetSym, 'local')) print('='); emitNode(print, node.val); if (context !== 'sval') print(';\n'); break; + case 'let': + if (context === 'sval') print('(function()'); + print('{'); + if (node.bindings.length) print('var '); + for (let i = 0; i < node.bindings.length; i++) { + const [name, val] = node.bindings[i]; + print(mungeSym(name, 'local')) + print('='); + emitNode(print, val); + if (i < node.bindings.length-1) print(','); + } + if (node.bindings.length) print(';'); + emitBlock(print, node.statements, node.ret); + print('}'); + if (context === 'sval') print(')()'); + break; case 'call': if (context === 'return') print('return '); emitNode(print, node.f);