cream-and-sugar
Version:
A deliciously functional syntax for JavaScript with native support for JSX
61 lines (57 loc) • 1.67 kB
JavaScript
import { compile, nodes, die } from '../utils';
function collectChain(orig, accum) {
orig.forEach(item => {
if (item.type === 'Pipe') {
accum.push(item.initVal.type === 'Wrap' ? item.initVal.item : item.initVal);
accum = accum.concat(collectChain(item.chain, []));
} else if (item.type === 'Wrap') {
accum.push(item.item);
} else {
accum.push(item);
}
});
return accum;
}
function meldChain(chain) {
const accum = [];
chain.forEach((currentNode, index) => {
if (index === 0) {
accum.push(currentNode);
} else {
let functionized;
switch (currentNode.type) {
case 'Identifier':
case 'Lookup':
functionized = new nodes.Functionizer(accum.pop());
accum.push(new nodes.FunctionCallNode(currentNode, {items:[functionized]}, currentNode.loc));
break;
case 'FunctionCall':
functionized = new nodes.Functionizer(accum.pop());
currentNode.args.items.push(functionized);
accum.push(currentNode);
break;
default:
throw new Error(`Can not use an expression of type ${currentNode.type} in a pipe.`);
}
}
});
return new nodes.Functionizer(accum.pop());
}
/*
* Translate scope piping chains.
*
* foo >>= bar 'a' >>= baz 'b'
*
* (function () {
* return baz('b', (function () {
* return bar('a', (function () {
* return foo
* }()))
* }()))
* }())
*/
compile(nodes.PipeNode, function () {
const flatChain = collectChain(this.chain, [this.initVal]);
const meldedChain = meldChain(flatChain);
return meldedChain.compile(true);
});