author | Alan Dipert
<alan@dipert.org> 2019-10-24 04:33:14 UTC |
committer | Alan Dipert
<alan@dipert.org> 2019-10-24 04:33:14 UTC |
parent | 1a385ccbbb65f6ef1387316e52c6264a54462a2d |
jacl.js | +36 | -1 |
diff --git a/jacl.js b/jacl.js index 0542de6..d6aaf4a 100644 --- a/jacl.js +++ b/jacl.js @@ -27,6 +27,9 @@ class Cons { return xs.reduce((a, b) => Cons.append(a,b)); } } + static toArray(cons) { + return cons ? Array.from(cons) : []; + } static listStar(...xs) { if (xs.length === 0) { throw new Error(`LIST* requires at least one argument`); @@ -906,6 +909,19 @@ const analyzeSpecials = new Map([ Object.assign(node, analyzeBlock(bodyEnv, node, exprs)); return node; }], + [JACLPKG.intern('%JS'), (env, parent, form) => { + const [, template, ...args] = form, + templateStr = template.toString(), + numPlaceholders = (templateStr.match(/~{}/g) || []).length; + + if (numPlaceholders !== args.length) + throw new Error(`%JS wrong number of arguments`); + + const node = makeNode('js', { env: env, parent: parent, form: form }); + node.args = args.map(x => analyze(env.withContext('sval'), node, x)); + node.template = templateStr; + return node; + }], [JACLPKG.intern('%LET'), (env, parent, form) => { const [, bindings, ...body] = form; const node = makeNode('let', { @@ -913,7 +929,7 @@ const analyzeSpecials = new Map([ parent: parent, form: form }); - node.bindings = Array.from(bindings).map(([name, expr]) => { + node.bindings = Cons.toArray(bindings).map(([name, expr]) => { return [name, analyze(env.withContext('sval'), node, expr)]; }); return merge( @@ -1208,6 +1224,25 @@ const emitNode = (print, node) => { emitNode(print, node.val); if (context !== 'sval') print(';\n'); break; + case 'js': + if (context === 'return') print('return '); + if (node.args.length) { + let template = node.template, + args = [...node.args], + end = -1; + while (true) { + end = template.indexOf('~{}'); + if (end < 0) break; + print(template.substring(0, end)); + emitNode(print, args.shift()); + template = template.substring(end+3); + } + print(template); + } else { + print(node.template); + } + if (context !== 'sval') print(';\n'); + break; case 'let': if (context === 'sval') print('(function()'); print('{');