├── AUTHORS ├── .gitignore ├── loopers ├── enumerator.js ├── iteratorObj.js ├── values.js ├── arrayRev.js ├── array.js ├── keyValues.js ├── ownKeys.js ├── ownValues.js ├── sparse.js ├── sparseRev.js ├── ownKeyValues.js ├── slice.js ├── sliceRev.js ├── iota.js ├── unfold.js └── scanText.js ├── .travis.yml ├── package.json ├── README.md ├── tests ├── tests.html ├── phantom.js └── tests.js ├── utils ├── loop.js └── translate.js ├── interpret.js ├── object.js ├── Pipe.js ├── arrayCompiler.js └── LICENSE /AUTHORS: -------------------------------------------------------------------------------- 1 | Eugene Lazutkin (http://lazutkin.com/) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | *.iml 3 | .idea 4 | *.sublime-* 5 | report/* 6 | coverage/* 7 | -------------------------------------------------------------------------------- /loopers/enumerator.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function", 8 | "for(var __i in __source){", 9 | " var value = __i;", 10 | " #{code}", 11 | "}" 12 | ] 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /loopers/iteratorObj.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// Java-like iterator object", 8 | "while(__source.hasNext()){", 9 | " var value = __source.next();", 10 | " #{code}", 11 | "}" 12 | ] 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /loopers/values.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function over values", 8 | "for(var __i in __source){", 9 | " var value = __source[__i];", 10 | " #{code}", 11 | "}" 12 | ] 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /loopers/arrayRev.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// reversed array-based iterator function", 8 | "for(var __i = __source.length; --__i >= 0;){", 9 | " var value = __source[__i];", 10 | " #{code}", 11 | "}" 12 | ] 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /loopers/array.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// array-based iterator function", 8 | "for(var __i = 0; __i < __source.length; ++__i){", 9 | " var value = __source[__i];", 10 | " #{code}", 11 | "}" 12 | ], 13 | true 14 | ); 15 | }); 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - "0.10" 7 | - "0.12" 8 | - "iojs" 9 | 10 | # env: 11 | # - PHANTOM=true 12 | # - PHANTOM=false 13 | 14 | # matrix: 15 | # exclude: 16 | # - node_js: "0.10" 17 | # env: PHANTOM=true 18 | # - node_js: "iojs" 19 | # env: PHANTOM=true 20 | 21 | # before_script: if [ "$PHANTOM" == "true" ]; then export RUN_TEST="phantomjs tests/phantom.js"; else export RUN_TEST="npm test"; fi 22 | 23 | # script: $RUN_TEST 24 | -------------------------------------------------------------------------------- /loopers/keyValues.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function over key-value-source triplets", 8 | "for(var __i in __source){", 9 | " var value = [__i, __source[__i], __source];", 10 | " #{code}", 11 | "}" 12 | ] 13 | ); 14 | }); 15 | -------------------------------------------------------------------------------- /loopers/ownKeys.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function over own keys", 8 | "for(var __i in __source){", 9 | " if(__source.hasOwnProperty(__i)){", 10 | " var value = __i;", 11 | " #{code}", 12 | " }", 13 | "}" 14 | ] 15 | ); 16 | }); 17 | -------------------------------------------------------------------------------- /loopers/ownValues.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function over own values", 8 | "for(var __i in __source){", 9 | " if(__source.hasOwnProperty(__i)){", 10 | " var value = __source[__i];", 11 | " #{code}", 12 | " }", 13 | "}" 14 | ] 15 | ); 16 | }); 17 | -------------------------------------------------------------------------------- /loopers/sparse.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// sparse array-based iterator function", 8 | "for(var __i = 0; __i < __source.length; ++__i){", 9 | " if(__i in __source){", 10 | " var value = __source[__i];", 11 | " #{code}", 12 | " }", 13 | "}" 14 | ] 15 | ); 16 | }); 17 | -------------------------------------------------------------------------------- /loopers/sparseRev.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// reversed sparse array-based iterator function", 8 | "for(var __i = __source.length; --__i >= 0;){", 9 | " if(__i in __source){", 10 | " var value = __source[__i];", 11 | " #{code}", 12 | " }", 13 | "}" 14 | ] 15 | ); 16 | }); 17 | -------------------------------------------------------------------------------- /loopers/ownKeyValues.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// for..in iterator function over own key-value-source triplets", 8 | "for(var __i in __source){", 9 | " if(__source.hasOwnProperty(__i)){", 10 | " var value = [__i, __source[__i], __source];", 11 | " #{code}", 12 | " }", 13 | "}" 14 | ] 15 | ); 16 | }); 17 | -------------------------------------------------------------------------------- /loopers/slice.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// array-based iterator function with slicing", 8 | "var __ib = __begin || 0, __ie = isNaN(__end) ? __source.length : __end;", 9 | "if(__ib < 0) __ib = __source.length + __ib;", 10 | "if(__ie < 0) __ie = __source.length + __ie;", 11 | "for(var __i = __ib; __i < __ie; ++__i){", 12 | " var value = __source[__i];", 13 | " #{code}", 14 | "}" 15 | ], 16 | false, 17 | ["__begin", "__end"] 18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /loopers/sliceRev.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// reversed array-based iterator function with slicing", 8 | "var __ib = __begin || 0, __ie = isNaN(__end) ? __source.length : __end;", 9 | "if(__ib < 0) __ib = __source.length + __ib;", 10 | "if(__ie < 0) __ie = __source.length + __ie;", 11 | "for(var __i = __ib - 1; __i >= __ie; --__i){", 12 | " var value = __source[__i];", 13 | " #{code}", 14 | "}" 15 | ], 16 | false, 17 | ["__begin", "__end"] 18 | ); 19 | }); 20 | -------------------------------------------------------------------------------- /loopers/iota.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop"], function(loop){ 3 | "use strict"; 4 | 5 | return loop( 6 | [ 7 | "// number sequence", 8 | "__to = isNaN(__to) ? Infinity : __to;", 9 | "__step = Math.abs(isNaN(__step) ? 1 : __step);", 10 | "var __if = __source, __it = __to, __is = __step;", 11 | "if(__it < __if){", 12 | " __if = -__source, __it = -__to, __is = -__is;", 13 | "}", 14 | "for(; __if < __it; __if += __step, __source += __is){", 15 | " var value = __source;", 16 | " #{code}", 17 | "}" 18 | ], 19 | false, 20 | ["__to", "__step"] // __from is __source 21 | ); 22 | }); 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heya-pipe", 3 | "version": "0.1.4", 4 | "description": "Pipe: a functional toolkit to build efficient data processing pipes.", 5 | "directories": { 6 | "test": "tests" 7 | }, 8 | "dependencies": { 9 | "heya-ctr": ">=0.1" 10 | }, 11 | "devDependencies": { 12 | "heya-unit": ">=0.1" 13 | }, 14 | "scripts": { 15 | "test": "node tests/tests.js" 16 | }, 17 | "amd": {}, 18 | "volo": { 19 | "type": "directory", 20 | "dependencies": { 21 | "heya-ctr": "heya/ctr" 22 | } 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git://github.com/heya/pipe.git" 27 | }, 28 | "keywords": [ 29 | "functional", 30 | "data processing", 31 | "code generation", 32 | "code construction" 33 | ], 34 | "author": "Eugene Lazutkin (http://lazutkin.com/)", 35 | "license": "BSD-3-Clause" 36 | } 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pipe 2 | 3 | [![Build status][travis-image]][travis-url] 4 | [![Dependencies][deps-image]][deps-url] 5 | [![devDependencies][dev-deps-image]][dev-deps-url] 6 | [![NPM version][npm-image]][npm-url] 7 | 8 | 9 | Pipe: a functional toolkit to build efficient data processing pipes. 10 | 11 | ## How to install 12 | 13 | If you plan to use it in your [node.js](http://nodejs.org) project install it 14 | like this: 15 | 16 | ``` 17 | npm install heya-pipe 18 | ``` 19 | 20 | For your browser-based projects I suggest to use [volo.js](http://volojs.org): 21 | 22 | ``` 23 | volo add -amdoff heya/pipe heya-pipe 24 | ``` 25 | 26 | [npm-image]: https://img.shields.io/npm/v/heya-pipe.svg 27 | [npm-url]: https://npmjs.org/package/heya-pipe 28 | [deps-image]: https://img.shields.io/david/heya/pipe.svg 29 | [deps-url]: https://david-dm.org/heya/pipe 30 | [dev-deps-image]: https://img.shields.io/david/dev/heya/pipe.svg 31 | [dev-deps-url]: https://david-dm.org/heya/pipe#info=devDependencies 32 | [travis-image]: https://img.shields.io/travis/heya/pipe.svg 33 | [travis-url]: https://travis-ci.org/heya/pipe 34 | -------------------------------------------------------------------------------- /tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | heya-pipe test runner 5 | 7 | 8 | 9 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /loopers/unfold.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/loop", "../Pipe"], function(loop, Pipe){ 3 | "use strict"; 4 | 5 | var tmplFun = loop( 6 | [ 7 | "// unfold-based iterator function", 8 | "for(;;){", 9 | " #{code}", 10 | "}" 11 | ] 12 | ); 13 | 14 | return function unfold(pred, value, next){ 15 | return function(pipe, name, isResultSpecified){ 16 | // The code below uses __source as a starting value, 17 | // and to hold intermediate values. 18 | // __source is the first argument of a generated function. 19 | var p = new Pipe(). 20 | forEach({ 21 | vars: ["__runNext", "accumulator", "value"], 22 | code: [ 23 | "accumulator = __source;", 24 | "if(__runNext){" 25 | ] 26 | }). 27 | forEach(next). 28 | forEach([ 29 | "__source = accumulator;", 30 | "}", 31 | "__runNext = true;" 32 | ]). 33 | takeWhile(pred). 34 | map(value). 35 | add(pipe); 36 | return tmplFun(p, name, isResultSpecified); 37 | }; 38 | }; 39 | }); 40 | -------------------------------------------------------------------------------- /tests/phantom.js: -------------------------------------------------------------------------------- 1 | phantom.onError = function(msg, trace){ 2 | var msgStack = ["PHANTOM ERROR: " + msg]; 3 | if(trace){ 4 | msgStack.push("TRACE:"); 5 | trace.forEach(function(t){ 6 | msgStack.push(" -> " + (t.file || t.sourceURL) + ": " + t.line + 7 | (t.function ? " (in function " + t.function + ")" : "")); 8 | }); 9 | } 10 | console.error(msgStack.join('\n')); 11 | phantom.exit(1); 12 | }; 13 | 14 | var page = require("webpage").create(); 15 | 16 | page.onError = function(msg){ 17 | console.error("ERROR: " + msg); 18 | phantom.exit(1); 19 | }; 20 | 21 | page.onAlert = function(msg){ 22 | console.log("ALERT: " + msg); 23 | }; 24 | page.onConsoleMessage = function(msg){ 25 | console.log(msg); 26 | }; 27 | page.onCallback = function(msg){ 28 | switch(msg){ 29 | case "success": 30 | phantom.exit(0); 31 | break; 32 | case "failure": 33 | phantom.exit(1); 34 | break; 35 | } 36 | } 37 | 38 | var scriptPath = require("system").args[0], 39 | path = require("fs").absolute( 40 | (scriptPath.length && scriptPath.charAt(0) == "/" ? "" : "./") + scriptPath).split("/"); 41 | 42 | path.pop(); 43 | path.push("tests.html"); 44 | 45 | page.open(path.join("/"), function(status){ 46 | if(status !== "success"){ 47 | console.error("ERROR: Can't load a web page."); 48 | phantom.exit(1); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /utils/loop.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["./translate", "heya-ctr"], function(translate, ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(${args}){", 7 | " #{ext}", 8 | " #{vars}", 9 | " #{head}", 10 | " #{body}", 11 | "})", 12 | "//@ sourceURL=#{name}" 13 | ], 14 | fTry = [ 15 | "try{", 16 | " #{body}", 17 | "}finally{", 18 | " #{tail}", 19 | "}" 20 | ]; 21 | 22 | return function loop(tmpl, isArraySrc, extraArgs){ 23 | return function(pipe, name, isResultSpecified){ 24 | var result = translate(pipe, true, isArraySrc, isResultSpecified); 25 | 26 | var body = ctr(tmpl, result).lines; 27 | if(result.tail.length){ 28 | body = ctr(fTry, {body: body, tail: result.tail}).lines; 29 | } 30 | if(result.ret){ 31 | body.push(result.ret); 32 | } 33 | 34 | var externals = result.ext, vars = result.vars, 35 | args = extraArgs ? [result.args[0]].concat(extraArgs, result.args.slice(1)): result.args; 36 | 37 | return ctr(fTmpl, { 38 | args: args.join(", "), 39 | ext: externals.length ? "var __e = __self.__e;" : undefined, 40 | vars: vars.length ? "var " + vars.join(", ") + ";" : undefined, 41 | head: result.head, 42 | body: body, 43 | name: name || ("/pipe/loop/" + pipe.getName()) 44 | }, externals.length && {__e: externals}); 45 | } 46 | }; 47 | }); 48 | -------------------------------------------------------------------------------- /loopers/scanText.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["../utils/translate", "heya-ctr"], function(translate, ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(${args}){", 7 | " #{ext}", 8 | " #{vars}", 9 | " #{head}", 10 | " #{body}", 11 | "})", 12 | "//@ sourceURL=#{name}" 13 | ], 14 | fNormal = [ 15 | "__refIndex = +__refIndex || 0;", 16 | "__source.replace(__regEx, function(){", 17 | " if(__stop) return '';", 18 | " var value = arguments[__refIndex];", 19 | " #{code}", 20 | "});" 21 | ], 22 | fTry = [ 23 | "try{", 24 | " #{body}", 25 | "}finally{", 26 | " #{tail}", 27 | "}" 28 | ]; 29 | 30 | return function(pipe, name){ 31 | var result = translate(pipe, false, false, false, true); 32 | 33 | var body = ctr(fNormal, result).lines; 34 | if(result.tail.length){ 35 | body = ctr(fTry, {body: body, tail: result.tail}).lines; 36 | } 37 | if(result.ret){ 38 | body.push(result.ret); 39 | } 40 | 41 | var externals = result.ext, vars = result.vars, 42 | args = ["__source, __regEx, __refIndex"].concat(result.args); 43 | 44 | return ctr(fTmpl, { 45 | args: args.join(", "), 46 | ext: externals.length ? "var __e = __self.__e;" : undefined, 47 | vars: vars.length ? "var " + vars.join(", ") + ";" : undefined, 48 | head: result.head, 49 | body: body, 50 | name: name || ("/pipe/scanText/" + pipe.getName()) 51 | }, externals.length && {__e: externals}); 52 | }; 53 | }); 54 | -------------------------------------------------------------------------------- /interpret.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | ([], function(){ 3 | "use strict"; 4 | 5 | //TODO: add asserts 6 | // code should be a function, 7 | // value-taking methods should have physical values supplied 8 | 9 | function interpret(pipe, array){ 10 | var stages = pipe.stages, len = stages.length, temp; 11 | for(var i = 0; i < len; ++i){ 12 | var stage = stages[i], f = stage.code; 13 | switch(stage.type){ 14 | case "forEach": 15 | array.forEach(f); 16 | break; 17 | case "transform": 18 | array.forEach(function(value, index, array){ 19 | array[index] = f(value, index); 20 | }); 21 | break; 22 | case "map": 23 | array = array.map(f); 24 | break; 25 | case "filter": 26 | array = array.filter(f); 27 | break; 28 | case "indexOf": 29 | return array.indexOf(stage.value); 30 | case "every": 31 | return array.every(f); 32 | case "some": 33 | return array.some(f); 34 | case "fold": 35 | return array.reduce(f, stage.value); 36 | case "scan": 37 | temp = stage.value; // accumulator 38 | array = array.map(function(value, index){ 39 | return temp = f(temp, value, index); 40 | }); 41 | temp = null; 42 | break; 43 | case "skip": 44 | temp = stage.value; 45 | array = array.filter(function(_, index){ 46 | return index >= temp; 47 | }); 48 | break; 49 | case "take": 50 | temp = stage.value; 51 | array = array.filter(function(_, index){ 52 | return index < temp; 53 | }); 54 | break; 55 | case "skipWhile": 56 | temp = false; 57 | array = array.filter(function(value, index){ 58 | return temp || (temp = !f(value, index)); 59 | }); 60 | break; 61 | case "takeWhile": 62 | temp = true; 63 | array = array.filter(function(value, index){ 64 | return temp && (temp = f(value, index)); 65 | }); 66 | break; 67 | case "voidResult": 68 | return; 69 | case "find": 70 | return array.find(f); 71 | case "findIndex": 72 | return array.findIndex(f); 73 | } 74 | } 75 | return array; 76 | } 77 | 78 | function curry(pipe){ 79 | return function(array){ 80 | return interpret(pipe, array); 81 | }; 82 | } 83 | 84 | interpret.curry = curry; 85 | 86 | return interpret; 87 | }); 88 | -------------------------------------------------------------------------------- /object.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["./utils/translate", "heya-ctr"], function(translate, ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function(${varList}){", 7 | " #{extDecl}", 8 | " return {", 9 | " start: function(${argList}){", 10 | " #{extInit}", 11 | " #{assignArgs}", 12 | " #{assignVars}", 13 | " #{undefineVars}", 14 | " #{head}", 15 | " },", 16 | " process: function(value, sink){", 17 | " if(__stop) return value;", 18 | " #{code}", 19 | " },", 20 | " stop: function(sink){", 21 | " #{tail}", 22 | " __stop = true;", 23 | " },", 24 | " isStopped: function(){ return __stop; },", 25 | " getResult: function(){", 26 | " #{ret}", 27 | " }", 28 | " };", 29 | "})()", 30 | "//@ sourceURL=#{name}" 31 | ]; 32 | 33 | return function object(pipe, name){ 34 | var result = translate(pipe), 35 | externals = result.ext, 36 | varList = result.args.concat(result.vars.map(function(value){ 37 | return /\b\w+\b/.exec(value)[0]; 38 | })).join(", "), 39 | argList = result.args.map(function(value, index){ 40 | return "__arg" + index; 41 | }).join(", "), 42 | assignArgs = result.args.map(function(value, index){ 43 | return value + " = __arg" + index + ";"; 44 | }), 45 | assignVars = result.vars.filter(function(value){ 46 | return value.indexOf("=") > 0; 47 | }).map(function(value){ 48 | return value + ";"; 49 | }), 50 | undefineVars = result.vars.filter(function(value){ 51 | return value.indexOf("=") < 0; 52 | }).join(" = "); 53 | 54 | undefineVars = undefineVars ? undefineVars + " = undefined;" : undefined; 55 | 56 | return ctr(fTmpl, { 57 | varList: varList, 58 | argList: argList, 59 | assignArgs: assignArgs, 60 | assignVars: assignVars, 61 | undefineVars: undefineVars, 62 | extDecl: externals.length ? "var __e;" : undefined, 63 | extInit: externals.length ? "__e = this.externals;" : undefined, 64 | head: result.head, 65 | code: result.code, 66 | tail: result.tail, 67 | ret: result.ret, 68 | name: name || ("/pipe/object/" + pipe.getName()) 69 | }, externals.length && {externals: externals}); 70 | }; 71 | }); 72 | -------------------------------------------------------------------------------- /Pipe.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | ([], function(){ 3 | "use strict"; 4 | 5 | var uniqNumber = 0; 6 | 7 | function Arg(name){ 8 | this.name = name; 9 | } 10 | 11 | function Pipe(){ 12 | this.stages = []; 13 | // stages is an array of objects with following components: 14 | // 15 | // type: a required string corresponding to one of 16 | // primitive operations (see below) 17 | // 18 | // Following optional properties represent an executable code 19 | // either by an array of strings, or as a function: 20 | // 21 | // code: this code is executed on every operation 22 | // head: this code is executed once before a loop 23 | // tail: this code is executed once after a loop 24 | // 25 | // Following optional properties represent a list of variables 26 | // as an array of strings: 27 | // 28 | // args: a list of additional argument names 29 | // vars: a list of additional internal variables 30 | // possibly with initializers 31 | // 32 | // value: a literal value required by some operations, or 33 | // an Arg object, which tells a name of an argument 34 | // receiving the value (should be in args already) 35 | } 36 | 37 | Pipe.Arg = Arg; 38 | Pipe.arg = function(name){ return new Arg(name); }; 39 | 40 | function prepareCode(code){ 41 | if(typeof code == "function"){ 42 | return code; 43 | } 44 | if(typeof code == "string"){ 45 | return code.split("\n"); 46 | } 47 | if(code && code instanceof Array){ 48 | return code.slice(0); 49 | } 50 | //TODO: add asserts 51 | return null; 52 | } 53 | 54 | Pipe.prototype = { 55 | add: function(type, stage, context, value){ 56 | if(type && type instanceof Pipe){ 57 | if(type.stages.length){ 58 | this.stages.push.apply(this.stages, type.stages); 59 | } 60 | return this; 61 | } 62 | var s = {type: type}; 63 | if(stage){ 64 | if(typeof stage == "string"){ 65 | s.code = stage.split("\n"); 66 | }else if(stage instanceof Array){ 67 | s.code = stage.slice(0); 68 | }else if(typeof stage == "function"){ 69 | s.code = context ? stage.bind(context) : stage; 70 | }else{ 71 | // copying arrays 72 | stage.args && (s.args = stage.args.slice(0)); 73 | stage.vars && (s.vars = stage.vars.slice(0)); 74 | stage.head && (s.head = prepareCode(stage.head)); 75 | stage.code && (s.code = prepareCode(stage.code)); 76 | stage.tail && (s.tail = prepareCode(stage.tail)); 77 | if(stage.hasOwnProperty("value")){ 78 | s.value = stage.value; 79 | } 80 | } 81 | } 82 | if(arguments.length > 3){ 83 | s.value = value; // literal value 84 | } 85 | this.stages.push(s); 86 | return this; 87 | }, 88 | 89 | getName: function(){ 90 | return this.stages.map(function(stage){ return stage.type; }).join("-") + 91 | "_" + (uniqNumber++) + ".js"; 92 | }, 93 | 94 | // standard operations 95 | 96 | forEach: function(code, context){ 97 | return this.add("forEach", code, context); 98 | }, 99 | transform: function(code, context){ 100 | return this.add("transform", code, context); 101 | }, 102 | map: function(code, context){ 103 | return this.add("map", code, context); 104 | }, 105 | filter: function(code, context){ 106 | return this.add("filter", code, context); 107 | }, 108 | indexOf: function(value){ 109 | return this.add("indexOf", null, null, value); 110 | }, 111 | every: function(code, context){ 112 | return this.add("every", code, context); 113 | }, 114 | some: function(code, context){ 115 | return this.add("some", code, context); 116 | }, 117 | fold: function(code, value){ 118 | return this.add("fold", code, null, value); 119 | }, 120 | scan: function(code, value){ 121 | return this.add("scan", code, null, value); 122 | }, 123 | skip: function(value){ 124 | return this.add("skip", null, null, value); 125 | }, 126 | take: function(value){ 127 | return this.add("take", null, null, value); 128 | }, 129 | skipWhile: function(code, context){ 130 | return this.add("skipWhile", code, context); 131 | }, 132 | takeWhile: function(code, context){ 133 | return this.add("takeWhile", code, context); 134 | }, 135 | voidResult: function(){ 136 | return this.add("voidResult"); 137 | }, 138 | find: function(code, context){ 139 | return this.add("find", code, context); 140 | }, 141 | findIndex: function(code, context){ 142 | return this.add("findIndex", code, context); 143 | } 144 | }; 145 | 146 | return Pipe; 147 | }); 148 | -------------------------------------------------------------------------------- /arrayCompiler.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["heya-ctr", "./Pipe"], function(ctr, Pipe){ 3 | "use strict"; 4 | 5 | function processCode(code, externals, list){ 6 | if(typeof code == "function"){ 7 | list.push("(__e[" + externals.length + "])();"); 8 | externals.push(code); 9 | }else{ 10 | list.push.apply(list, code); 11 | } 12 | } 13 | 14 | function makePredicate(tail, lines){ 15 | var last = lines.length - 1; 16 | return lines.slice(0, last).concat( 17 | ctr(tail, {pred: lines[last]}).lines 18 | ); 19 | } 20 | 21 | function makeBlock(head, tail, lines){ 22 | return ctr(head + "\n #{code}\n" + tail, {code: lines}).lines; 23 | } 24 | 25 | function arrayCompiler(pipe, name){ 26 | var args = ["__array"], argsDict = {__array: 1}, 27 | vars = [], head = [], tail = [], code = [], 28 | externals = [], f, v, temp, temp2, voidResult, 29 | stages = pipe.stages, len = stages.length; 30 | loop: for(var i = 0; i < len; ++i){ 31 | var stage = stages[i]; 32 | 33 | // process common parts 34 | if(stage.args){ 35 | for(var j = 0; j < stage.args.length; ++j){ 36 | temp = stage.args[j]; 37 | if(!argsDict.hasOwnProperty(temp)){ 38 | argsDict[temp] = 1; 39 | args.push(temp); 40 | } 41 | } 42 | } 43 | if(stage.vars){ 44 | vars.push.apply(vars, stage.vars); 45 | } 46 | if(stage.head){ 47 | processCode(stage.head, externals, head); 48 | } 49 | if(stage.tail){ 50 | processCode(stage.tail, externals, tail); 51 | } 52 | 53 | f = stage.code; 54 | switch(stage.type){ 55 | case "forEach": 56 | if(typeof f == "function"){ 57 | code.push("__array.forEach(__e[" + externals.length + "]);"); 58 | externals.push(f); 59 | }else{ 60 | code.push.apply(code, makeBlock( 61 | "__array.forEach(function(value, index){", 62 | "});", 63 | f 64 | )); 65 | } 66 | break; 67 | case "transform": 68 | if(typeof f == "function"){ 69 | temp = "__array[index] = (__e[" + 70 | externals.length + "])(value, index);"; 71 | externals.push(f); 72 | }else{ 73 | temp = f.slice(0); 74 | temp.push("__array[index] = value;"); 75 | } 76 | code.push.apply(code, makeBlock( 77 | "__array.forEach(function(value, index, __array){", 78 | "});", 79 | temp 80 | )); 81 | break; 82 | case "map": 83 | if(typeof f == "function"){ 84 | code.push("__array = __array.map(__e[" + externals.length + "]);"); 85 | externals.push(f); 86 | }else{ 87 | temp = f.slice(0); 88 | temp.push("return value;"); 89 | code.push.apply(code, makeBlock( 90 | "__array = __array.map(function(value, index){", 91 | "});", 92 | temp 93 | )); 94 | } 95 | break; 96 | case "filter": 97 | if(typeof f == "function"){ 98 | code.push("__array = __array.filter(__e[" + externals.length + "]);"); 99 | externals.push(f); 100 | }else{ 101 | code.push.apply(code, makeBlock( 102 | "__array = __array.filter(function(value, index){", 103 | "});", 104 | makePredicate("return ${pred};", f) 105 | )); 106 | } 107 | break; 108 | case "indexOf": 109 | v = stage.value; 110 | if(v && v instanceof Pipe.Arg){ 111 | temp = v.name; 112 | if(!argsDict.hasOwnProperty(temp)){ 113 | argsDict[temp] = 1; 114 | args.push(temp); 115 | } 116 | }else{ 117 | temp = "__e[" + externals.length + "]"; 118 | externals.push(v); 119 | } 120 | code.push("__array = __array.indexOf(" + temp + ");"); 121 | break loop; 122 | case "every": 123 | if(typeof f == "function"){ 124 | code.push("__array = __array.every(__e[" + externals.length + "]);"); 125 | externals.push(f); 126 | }else{ 127 | code.push.apply(code, makeBlock( 128 | "__array = __array.every(function(value, index){", 129 | "});", 130 | makePredicate("return ${pred};", f) 131 | )); 132 | } 133 | break loop; 134 | case "some": 135 | if(typeof f == "function"){ 136 | code.push("__array = __array.some(__e[" + externals.length + "]);"); 137 | externals.push(f); 138 | }else{ 139 | code.push.apply(code, makeBlock( 140 | "__array = __array.some(function(value, index){", 141 | "});", 142 | makePredicate("return ${pred};", f) 143 | )); 144 | } 145 | break loop; 146 | case "fold": 147 | v = stage.value; 148 | if(v && v instanceof Pipe.Arg){ 149 | temp = v.name; 150 | if(!argsDict.hasOwnProperty(temp)){ 151 | argsDict[temp] = 1; 152 | args.push(temp); 153 | } 154 | }else{ 155 | temp = "__e[" + externals.length + "]"; 156 | externals.push(v); 157 | } 158 | if(typeof f == "function"){ 159 | code.push("__array = __array.reduce(__e[" + externals.length + "], " + temp + ");"); 160 | externals.push(f); 161 | }else{ 162 | code.push.apply(code, makeBlock( 163 | "__array = __array.reduce(function(accumulator, value, index){", 164 | "}, " + temp + ");", 165 | f.concat(["return accumulator;"]) 166 | )); 167 | } 168 | break loop; 169 | case "scan": 170 | v = stage.value; 171 | if(v && v instanceof Pipe.Arg){ 172 | temp = v.name; 173 | if(!argsDict.hasOwnProperty(temp)){ 174 | argsDict[temp] = 1; 175 | args.push(temp); 176 | } 177 | }else{ 178 | temp = "__e[" + externals.length + "]"; 179 | externals.push(v); 180 | } 181 | if(typeof f == "function"){ 182 | temp2 = "return accumulator = (__e[" + externals.length + "])(accumulator, value, index);"; 183 | externals.push(f); 184 | }else{ 185 | temp2 = f.concat(["return accumulator;"]); 186 | } 187 | code.push.apply(code, makeBlock( 188 | "__array = __array.map((function(accumulator){ return function(value, index){", 189 | "}})(" + temp + "));", 190 | temp2 191 | )); 192 | break; 193 | case "skip": 194 | v = stage.value; 195 | if(v && v instanceof Pipe.Arg){ 196 | temp = v.name; 197 | if(!argsDict.hasOwnProperty(temp)){ 198 | argsDict[temp] = 1; 199 | args.push(temp); 200 | } 201 | }else{ 202 | temp = "__e[" + externals.length + "]"; 203 | externals.push(v); 204 | } 205 | code.push.apply(code, makeBlock( 206 | "__array = __array.filter(function(value, index){", 207 | "});", 208 | "return index >= " + temp + ";" 209 | )); 210 | break; 211 | case "take": 212 | v = stage.value; 213 | if(v && v instanceof Pipe.Arg){ 214 | temp = v.name; 215 | if(!argsDict.hasOwnProperty(temp)){ 216 | argsDict[temp] = 1; 217 | args.push(temp); 218 | } 219 | }else{ 220 | temp = "__e[" + externals.length + "]"; 221 | externals.push(v); 222 | } 223 | code.push.apply(code, makeBlock( 224 | "__array = __array.filter(function(value, index){", 225 | "});", 226 | "return index < " + temp + ";" 227 | )); 228 | break; 229 | case "skipWhile": 230 | if(typeof f == "function"){ 231 | temp = "return __flag || (__flag = !(__e[" + externals.length + "])(value, index));"; 232 | externals.push(f); 233 | }else{ 234 | temp = makePredicate( 235 | "return __flag || (__flag = !(${pred}));", 236 | f 237 | ); 238 | } 239 | code.push.apply(code, makeBlock( 240 | "__array = __array.filter((function(__flag){ return function(value, index){", 241 | "}})(false));", 242 | temp 243 | )); 244 | break; 245 | case "takeWhile": 246 | if(typeof f == "function"){ 247 | temp = "return __flag && (__flag = (__e[" + externals.length + "])(value, index));"; 248 | externals.push(f); 249 | }else{ 250 | temp = makePredicate( 251 | "return __flag && (__flag = (${pred}));", 252 | f 253 | ); 254 | } 255 | code.push.apply(code, makeBlock( 256 | "__array = __array.filter((function(__flag){ return function(value, index){", 257 | "}})(true));", 258 | temp 259 | )); 260 | break; 261 | case "voidResult": 262 | voidResult = true; 263 | break loop; 264 | case "find": 265 | if(typeof f == "function"){ 266 | code.push("__array = __array.find(__e[" + externals.length + "]);"); 267 | externals.push(f); 268 | }else{ 269 | code.push.apply(code, makeBlock( 270 | "__array = __array.find(function(value, index){", 271 | "});", 272 | makePredicate("return ${pred};", f) 273 | )); 274 | } 275 | break loop; 276 | case "findIndex": 277 | if(typeof f == "function"){ 278 | code.push("__array = __array.findIndex(__e[" + externals.length + "]);"); 279 | externals.push(f); 280 | }else{ 281 | code.push.apply(code, makeBlock( 282 | "__array = __array.findIndex(function(value, index){", 283 | "});", 284 | makePredicate("return ${pred};", f) 285 | )); 286 | } 287 | break loop; 288 | } 289 | } 290 | 291 | // final code construction 292 | 293 | if(!voidResult){ 294 | code.push("return __array;"); 295 | } 296 | 297 | if(tail.length){ 298 | code = ctr([ 299 | "try{", 300 | " #{code}", 301 | "}finally{", 302 | " #{tail}", 303 | "}" 304 | ], {code: code, tail: tail}).lines; 305 | } 306 | 307 | return ctr( 308 | [ 309 | "(function __self(${args}){", 310 | " #{ext}", 311 | " #{vars}", 312 | " #{head}", 313 | " #{code}", 314 | "})", 315 | "//@ sourceURL=#{name}" 316 | ], 317 | { 318 | ext: externals.length ? "var __e = __self.__e;" : undefined, 319 | args: args.join(", "), 320 | vars: vars.length ? "var " + vars.join(", ") + ";" : undefined, 321 | head: head, 322 | code: code, 323 | name: name || ("/pipe/arrayCompiler/" + pipe.getName()) 324 | }, 325 | externals.length ? {__e: externals} : null 326 | ); 327 | } 328 | 329 | return arrayCompiler; 330 | }); 331 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This library is available under *either* the terms of the modified BSD license 2 | *or* the Academic Free License version 2.1. As a recipient of this work, you 3 | may choose which license to receive this code under. No external contributions 4 | are allowed under licenses which are fundamentally incompatible with the AFL 5 | or BSD licenses that this library is distributed under. 6 | 7 | The text of the AFL and BSD licenses is reproduced below. 8 | 9 | ------------------------------------------------------------------------------- 10 | The "New" BSD License: 11 | ********************** 12 | 13 | Copyright (c) 2005-2012, Eugene Lazutkin 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | 19 | * Redistributions of source code must retain the above copyright notice, this 20 | list of conditions and the following disclaimer. 21 | * Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | * Neither the name of Eugene Lazutkin nor the names of other contributors 25 | may be used to endorse or promote products derived from this software 26 | without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 29 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 32 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | 39 | ------------------------------------------------------------------------------- 40 | The Academic Free License, v. 2.1: 41 | ********************************** 42 | 43 | This Academic Free License (the "License") applies to any original work of 44 | authorship (the "Original Work") whose owner (the "Licensor") has placed the 45 | following notice immediately following the copyright notice for the Original 46 | Work: 47 | 48 | Licensed under the Academic Free License version 2.1 49 | 50 | 1) Grant of Copyright License. Licensor hereby grants You a world-wide, 51 | royalty-free, non-exclusive, perpetual, sublicenseable license to do the 52 | following: 53 | 54 | a) to reproduce the Original Work in copies; 55 | 56 | b) to prepare derivative works ("Derivative Works") based upon the Original 57 | Work; 58 | 59 | c) to distribute copies of the Original Work and Derivative Works to the 60 | public; 61 | 62 | d) to perform the Original Work publicly; and 63 | 64 | e) to display the Original Work publicly. 65 | 66 | 2) Grant of Patent License. Licensor hereby grants You a world-wide, 67 | royalty-free, non-exclusive, perpetual, sublicenseable license, under patent 68 | claims owned or controlled by the Licensor that are embodied in the Original 69 | Work as furnished by the Licensor, to make, use, sell and offer for sale the 70 | Original Work and Derivative Works. 71 | 72 | 3) Grant of Source Code License. The term "Source Code" means the preferred 73 | form of the Original Work for making modifications to it and all available 74 | documentation describing how to modify the Original Work. Licensor hereby 75 | agrees to provide a machine-readable copy of the Source Code of the Original 76 | Work along with each copy of the Original Work that Licensor distributes. 77 | Licensor reserves the right to satisfy this obligation by placing a 78 | machine-readable copy of the Source Code in an information repository 79 | reasonably calculated to permit inexpensive and convenient access by You for as 80 | long as Licensor continues to distribute the Original Work, and by publishing 81 | the address of that information repository in a notice immediately following 82 | the copyright notice that applies to the Original Work. 83 | 84 | 4) Exclusions From License Grant. Neither the names of Licensor, nor the names 85 | of any contributors to the Original Work, nor any of their trademarks or 86 | service marks, may be used to endorse or promote products derived from this 87 | Original Work without express prior written permission of the Licensor. Nothing 88 | in this License shall be deemed to grant any rights to trademarks, copyrights, 89 | patents, trade secrets or any other intellectual property of Licensor except as 90 | expressly stated herein. No patent license is granted to make, use, sell or 91 | offer to sell embodiments of any patent claims other than the licensed claims 92 | defined in Section 2. No right is granted to the trademarks of Licensor even if 93 | such marks are included in the Original Work. Nothing in this License shall be 94 | interpreted to prohibit Licensor from licensing under different terms from this 95 | License any Original Work that Licensor otherwise would have a right to 96 | license. 97 | 98 | 5) This section intentionally omitted. 99 | 100 | 6) Attribution Rights. You must retain, in the Source Code of any Derivative 101 | Works that You create, all copyright, patent or trademark notices from the 102 | Source Code of the Original Work, as well as any notices of licensing and any 103 | descriptive text identified therein as an "Attribution Notice." You must cause 104 | the Source Code for any Derivative Works that You create to carry a prominent 105 | Attribution Notice reasonably calculated to inform recipients that You have 106 | modified the Original Work. 107 | 108 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that 109 | the copyright in and to the Original Work and the patent rights granted herein 110 | by Licensor are owned by the Licensor or are sublicensed to You under the terms 111 | of this License with the permission of the contributor(s) of those copyrights 112 | and patent rights. Except as expressly stated in the immediately proceeding 113 | sentence, the Original Work is provided under this License on an "AS IS" BASIS 114 | and WITHOUT WARRANTY, either express or implied, including, without limitation, 115 | the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR 116 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. 117 | This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No 118 | license to Original Work is granted hereunder except under this disclaimer. 119 | 120 | 8) Limitation of Liability. Under no circumstances and under no legal theory, 121 | whether in tort (including negligence), contract, or otherwise, shall the 122 | Licensor be liable to any person for any direct, indirect, special, incidental, 123 | or consequential damages of any character arising as a result of this License 124 | or the use of the Original Work including, without limitation, damages for loss 125 | of goodwill, work stoppage, computer failure or malfunction, or any and all 126 | other commercial damages or losses. This limitation of liability shall not 127 | apply to liability for death or personal injury resulting from Licensor's 128 | negligence to the extent applicable law prohibits such limitation. Some 129 | jurisdictions do not allow the exclusion or limitation of incidental or 130 | consequential damages, so this exclusion and limitation may not apply to You. 131 | 132 | 9) Acceptance and Termination. If You distribute copies of the Original Work or 133 | a Derivative Work, You must make a reasonable effort under the circumstances to 134 | obtain the express assent of recipients to the terms of this License. Nothing 135 | else but this License (or another written agreement between Licensor and You) 136 | grants You permission to create Derivative Works based upon the Original Work 137 | or to exercise any of the rights granted in Section 1 herein, and any attempt 138 | to do so except under the terms of this License (or another written agreement 139 | between Licensor and You) is expressly prohibited by U.S. copyright law, the 140 | equivalent laws of other countries, and by international treaty. Therefore, by 141 | exercising any of the rights granted to You in Section 1 herein, You indicate 142 | Your acceptance of this License and all of its terms and conditions. 143 | 144 | 10) Termination for Patent Action. This License shall terminate automatically 145 | and You may no longer exercise any of the rights granted to You by this License 146 | as of the date You commence an action, including a cross-claim or counterclaim, 147 | against Licensor or any licensee alleging that the Original Work infringes a 148 | patent. This termination provision shall not apply for an action alleging 149 | patent infringement by combinations of the Original Work with other software or 150 | hardware. 151 | 152 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this 153 | License may be brought only in the courts of a jurisdiction wherein the 154 | Licensor resides or in which Licensor conducts its primary business, and under 155 | the laws of that jurisdiction excluding its conflict-of-law provisions. The 156 | application of the United Nations Convention on Contracts for the International 157 | Sale of Goods is expressly excluded. Any use of the Original Work outside the 158 | scope of this License or after its termination shall be subject to the 159 | requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et 160 | seq., the equivalent laws of other countries, and international treaty. This 161 | section shall survive the termination of this License. 162 | 163 | 12) Attorneys Fees. In any action to enforce the terms of this License or 164 | seeking damages relating thereto, the prevailing party shall be entitled to 165 | recover its costs and expenses, including, without limitation, reasonable 166 | attorneys' fees and costs incurred in connection with such action, including 167 | any appeal of such action. This section shall survive the termination of this 168 | License. 169 | 170 | 13) Miscellaneous. This License represents the complete agreement concerning 171 | the subject matter hereof. If any provision of this License is held to be 172 | unenforceable, such provision shall be reformed only to the extent necessary to 173 | make it enforceable. 174 | 175 | 14) Definition of "You" in This License. "You" throughout this License, whether 176 | in upper or lower case, means an individual or a legal entity exercising rights 177 | under, and complying with all of the terms of, this License. For legal 178 | entities, "You" includes any entity that controls, is controlled by, or is 179 | under common control with you. For purposes of this definition, "control" means 180 | (i) the power, direct or indirect, to cause the direction or management of such 181 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 182 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of such 183 | entity. 184 | 185 | 15) Right to Use. You may use the Original Work in all ways not otherwise 186 | restricted or conditioned by this License or by law, and Licensor promises not 187 | to interfere with or be responsible for such uses by You. 188 | 189 | This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. 190 | Permission is hereby granted to copy and distribute this license without 191 | modification. This license may not be modified without the express written 192 | permission of its copyright owner. 193 | -------------------------------------------------------------------------------- /utils/translate.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["heya-ctr", "../Pipe"], function(ctr, Pipe){ 3 | "use strict"; 4 | 5 | function processCode(code, externals, list){ 6 | if(typeof code == "function"){ 7 | list.push("(__e[" + externals.length + "])();"); 8 | externals.push(code); 9 | }else{ 10 | list.push.apply(list, code); 11 | } 12 | } 13 | 14 | function makePredicate(tail, lines){ 15 | var len = lines.length; 16 | return lines.slice(0, len - 1).concat( 17 | ctr(tail, {pred: lines[len - 1]}).lines 18 | ); 19 | } 20 | 21 | function makeBlock(head, tail, lines){ 22 | return ctr(head + "\n #{code}\n" + tail, {code: lines}).lines; 23 | } 24 | 25 | var useIndex = {indexOf: 1, skip: 1, take: 1, findIndex: 1}; 26 | 27 | function translate(pipe, isLoopEnv, isArraySrc, isResultSpecified, isReturnEmpty){ 28 | var args = [], argsDict = {}, 29 | vars = [], head = [], tail = [], code = [], 30 | externals = [], f, v, temp, temp2, voidResult, defaultReturn, 31 | dupped, skipped, noIndex = true, 32 | indexLevel = 0, flagLevel = 0, accLevel = 0, 33 | stages = pipe.stages, len = stages.length; 34 | 35 | if(isLoopEnv){ 36 | args.push("__source"); 37 | if(isResultSpecified){ 38 | args.push("__result"); 39 | } 40 | }else{ 41 | vars.push("__stop"); 42 | } 43 | 44 | loop: for(var i = 0; i < len; ++i){ 45 | var stage = stages[i]; 46 | 47 | // process common parts 48 | if(stage.args){ 49 | for(var j = 0; j < stage.args.length; ++j){ 50 | temp = stage.args[j]; 51 | if(!argsDict.hasOwnProperty(temp)){ 52 | argsDict[temp] = 1; 53 | args.push(temp); 54 | } 55 | } 56 | } 57 | if(stage.vars){ 58 | vars.push.apply(vars, stage.vars); 59 | } 60 | if(stage.head){ 61 | processCode(stage.head, externals, head); 62 | } 63 | if(stage.tail){ 64 | processCode(stage.tail, externals, tail); 65 | } 66 | 67 | // initialize index if required 68 | f = stage.code; 69 | if(noIndex){ 70 | temp = f && (typeof f == "function" || /\bindex\b/.test(f.join("\n"))) || 71 | stage.type == "transform" && isLoopEnv && isArraySrc && !dupped; 72 | if(temp || useIndex[stage.type]){ 73 | temp = "__i" + (indexLevel++); 74 | vars.push(temp + " = 0"); 75 | code.push("index = " + temp + "++;"); 76 | noIndex = false; 77 | } 78 | } 79 | 80 | switch(stage.type){ 81 | case "forEach": 82 | if(typeof f == "function"){ 83 | code.push("(__e[" + externals.length + "])(value, index);"); 84 | externals.push(f); 85 | }else{ 86 | code.push.apply(code, f); 87 | } 88 | break; 89 | case "transform": 90 | if(typeof f == "function"){ 91 | code.push("value = (__e[" + externals.length + "])(value, index);"); 92 | externals.push(f); 93 | }else{ 94 | code.push.apply(code, f); 95 | } 96 | if(isLoopEnv && isArraySrc && !dupped){ 97 | code.push("__source[index] = value;"); 98 | } 99 | break; 100 | case "map": 101 | if(typeof f == "function"){ 102 | code.push("value = (__e[" + externals.length + "])(value, index);"); 103 | externals.push(f); 104 | }else{ 105 | code.push.apply(code, f); 106 | } 107 | dupped = true; 108 | break; 109 | case "filter": 110 | temp = isLoopEnv ? "continue;" : (isReturnEmpty ? "return '';" : "return;"); 111 | if(typeof f == "function"){ 112 | code.push("if(!(__e[" + externals.length + "])(value, index)) " + temp + ";"); 113 | externals.push(f); 114 | }else{ 115 | code.push.apply(code, makePredicate("if(!(${pred})) " + temp, f)); 116 | } 117 | noIndex = skipped = dupped = true; 118 | break; 119 | case "indexOf": 120 | v = stage.value; 121 | if(v && v instanceof Pipe.Arg){ 122 | temp = v.name; 123 | if(!argsDict.hasOwnProperty(temp)){ 124 | argsDict[temp] = 1; 125 | args.push(temp); 126 | } 127 | }else{ 128 | temp = "__e[" + externals.length + "]"; 129 | externals.push(v); 130 | } 131 | code.push("if(value === " + temp + ")" + 132 | (isLoopEnv ? " return index;" : ("{ __stop = true; " + 133 | (isReturnEmpty ? "__result = index; return ''" : "return __result = index") + "; }"))); 134 | if(isLoopEnv){ 135 | defaultReturn = "return -1;"; 136 | }else{ 137 | vars.push("__result = -1"); 138 | defaultReturn = "return __result;"; 139 | } 140 | break loop; 141 | case "every": 142 | temp = isLoopEnv ? " return false;" : ("{ __stop = true; " + 143 | (isReturnEmpty ? "__result = false; return ''" : "return __result = false") + "; }"); 144 | if(typeof f == "function"){ 145 | code.push("if(!(__e[" + externals.length + "])(value, index))" + temp); 146 | externals.push(f); 147 | }else{ 148 | code.push.apply(code, makePredicate("if(!(${pred}))" + temp, f)); 149 | } 150 | if(isLoopEnv){ 151 | defaultReturn = "return true;"; 152 | }else{ 153 | vars.push("__result = true"); 154 | defaultReturn = "return __result;"; 155 | } 156 | break loop; 157 | case "some": 158 | temp = isLoopEnv ? " return true;" : ("{ __stop = true; " + 159 | (isReturnEmpty ? "__result = true; return ''" : "return __result = true") + "; }"); 160 | if(typeof f == "function"){ 161 | code.push("if((__e[" + externals.length + "])(value, index))" + temp); 162 | externals.push(f); 163 | }else{ 164 | code.push.apply(code, makePredicate("if(${pred})" + temp, f)); 165 | } 166 | if(isLoopEnv){ 167 | defaultReturn = "return false;"; 168 | }else{ 169 | vars.push("__result = false"); 170 | defaultReturn = "return __result;"; 171 | } 172 | break loop; 173 | case "fold": 174 | v = stage.value; 175 | if(v && v instanceof Pipe.Arg){ 176 | temp = v.name; 177 | if(!argsDict.hasOwnProperty(temp)){ 178 | argsDict[temp] = 1; 179 | args.push(temp); 180 | } 181 | }else{ 182 | temp = "__e[" + externals.length + "]"; 183 | externals.push(v); 184 | } 185 | if(!argsDict.hasOwnProperty("accumulator")){ 186 | vars.push("accumulator = " + temp); 187 | } 188 | if(typeof f == "function"){ 189 | code.push("accumulator = (__e[" + externals.length + "])(accumulator, value, index);"); 190 | externals.push(f); 191 | }else{ 192 | code.push.apply(code, f); 193 | } 194 | defaultReturn = "return accumulator;"; 195 | break loop; 196 | case "scan": 197 | v = stage.value; 198 | if(v && v instanceof Pipe.Arg){ 199 | temp = v.name; 200 | if(!argsDict.hasOwnProperty(temp)){ 201 | argsDict[temp] = 1; 202 | args.push(temp); 203 | } 204 | }else{ 205 | temp = "__e[" + externals.length + "]"; 206 | externals.push(v); 207 | } 208 | if(!argsDict.hasOwnProperty("accumulator")){ 209 | vars.push("accumulator"); 210 | } 211 | temp2 = "__acc" + (accLevel++); 212 | vars.push(temp2 + " = " + temp); 213 | if(typeof f == "function"){ 214 | code.push("value = " + temp2 + " = (__e[" + 215 | externals.length + "])(" + temp2 + ", value, index);"); 216 | externals.push(f); 217 | }else{ 218 | code.push("accumulator = " + temp2 + ";"); 219 | code.push.apply(code, f); 220 | code.push(temp2 + " = value = accumulator;"); 221 | } 222 | dupped = true; 223 | break; 224 | case "skip": 225 | v = stage.value; 226 | if(v && v instanceof Pipe.Arg){ 227 | temp = v.name; 228 | if(!argsDict.hasOwnProperty(temp)){ 229 | argsDict[temp] = 1; 230 | args.push(temp); 231 | } 232 | }else{ 233 | temp = "__e[" + externals.length + "]"; 234 | externals.push(v); 235 | } 236 | temp2 = isLoopEnv ? "continue;" : (isReturnEmpty ? "return '';" : "return;"); 237 | code.push("if(index < " + temp + ") " + temp2); 238 | noIndex = skipped = dupped = true; 239 | break; 240 | case "take": 241 | v = stage.value; 242 | if(v && v instanceof Pipe.Arg){ 243 | temp = v.name; 244 | if(!argsDict.hasOwnProperty(temp)){ 245 | argsDict[temp] = 1; 246 | args.push(temp); 247 | } 248 | }else{ 249 | temp = "__e[" + externals.length + "]"; 250 | externals.push(v); 251 | } 252 | temp2 = isLoopEnv ? " break;" : ("{ __stop = true; " + 253 | (isReturnEmpty ? "return ''" : "return") + "; }"); 254 | code.push("if(index >= " + temp + ")" + temp2); 255 | noIndex = skipped = dupped = true; 256 | break; 257 | case "skipWhile": 258 | temp = "__flag" + (flagLevel++); 259 | vars.push(temp + " = true"); 260 | temp2 = isLoopEnv ? "continue;" : (isReturnEmpty ? "return '';" : "return;"); 261 | if(typeof f == "function"){ 262 | code.push("if(" + temp + " || (" + temp + " = !(__e[" + externals.length + "])(value, index)))) " + temp2); 263 | externals.push(f); 264 | }else{ 265 | code.push.apply(code, makeBlock( 266 | "if(" + temp + "){", 267 | "}", 268 | makePredicate( 269 | "if(" + temp + " = (${pred})) " + temp2, 270 | f 271 | ) 272 | )); 273 | } 274 | noIndex = skipped = dupped = true; 275 | break; 276 | case "takeWhile": 277 | temp2 = isLoopEnv ? " break;" : ("{ __stop = true; " + 278 | (isReturnEmpty ? "return ''" : "return") + "; }"); 279 | if(typeof f == "function"){ 280 | code.push("if(!(__e[" + externals.length + "])(value, index)))" + temp2); 281 | externals.push(f); 282 | }else{ 283 | code.push.apply(code, makePredicate("if(!(${pred}))" + temp2, f)); 284 | } 285 | noIndex = skipped = dupped = true; 286 | break; 287 | case "voidResult": 288 | voidResult = true; 289 | break loop; 290 | case "find": 291 | temp = isLoopEnv ? " return value;" : ("{ __stop = true; " + 292 | (isReturnEmpty ? "__result = value; return ''" : "return __result = value") + "; }"); 293 | if(typeof f == "function"){ 294 | code.push("if((__e[" + externals.length + "])(value, index))" + temp); 295 | externals.push(f); 296 | }else{ 297 | code.push.apply(code, makePredicate("if(${pred})" + temp, f)); 298 | } 299 | if(isLoopEnv){ 300 | defaultReturn = "return;"; 301 | }else{ 302 | vars.push("__result"); 303 | defaultReturn = "return __result;"; 304 | } 305 | break loop; 306 | case "findIndex": 307 | temp = isLoopEnv ? " return index;" : ("{ __stop = true; " + 308 | (isReturnEmpty ? "__result = index; return ''" : "return __result = index") + "; }"); 309 | if(typeof f == "function"){ 310 | code.push("if((__e[" + externals.length + "])(value, index))" + temp); 311 | externals.push(f); 312 | }else{ 313 | code.push.apply(code, makePredicate("if(${pred})" + temp, f)); 314 | } 315 | if(isLoopEnv){ 316 | defaultReturn = "return -1;"; 317 | }else{ 318 | vars.push("__result = -1"); 319 | defaultReturn = "return __result;"; 320 | } 321 | break loop; 322 | } 323 | } 324 | 325 | if(isLoopEnv){ 326 | if(voidResult || defaultReturn){ 327 | // nothing 328 | }else if(isResultSpecified){ 329 | code.push("__result.push(value);"); 330 | if(!voidResult && !defaultReturn){ 331 | defaultReturn = "return __result;"; 332 | } 333 | }else if(dupped || !isArraySrc){ 334 | temp2 = isArraySrc && !skipped; 335 | if(noIndex && temp2){ 336 | temp = "__i" + (indexLevel++); 337 | vars.push(temp + " = 0"); 338 | code.push("index = " + temp + "++;"); 339 | noIndex = false; 340 | } 341 | vars.push("__result = " + (temp2 ? "new Array(__source.length)" : "[]")); 342 | code.push("__result" + (temp2 ? "[index] = value;" : ".push(value);")); 343 | if(!voidResult && !defaultReturn){ 344 | defaultReturn = "return __result;"; 345 | } 346 | }else{ 347 | if(!voidResult && !defaultReturn){ 348 | defaultReturn = "return __source;"; 349 | } 350 | } 351 | }else{ 352 | code.push("return value;"); 353 | } 354 | 355 | if(indexLevel){ 356 | vars.push("index"); 357 | } 358 | 359 | return { 360 | args: args, 361 | vars: vars, 362 | head: head, 363 | code: code, 364 | tail: tail, 365 | voidResult: voidResult, 366 | ret: defaultReturn, 367 | ext: externals 368 | }; 369 | } 370 | 371 | return translate; 372 | }); 373 | -------------------------------------------------------------------------------- /tests/tests.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["module", "heya-unit", 3 | "heya-ctr/evalWithEnv", "../Pipe", 4 | "../interpret", "../arrayCompiler", 5 | "../loopers/array", "../loopers/arrayRev", 6 | "../loopers/sparse", "../loopers/sparseRev", 7 | "../loopers/slice", "../loopers/sliceRev", 8 | "../loopers/enumerator", "../loopers/values", 9 | "../loopers/ownKeys", "../loopers/ownValues", 10 | "../loopers/keyValues", "../loopers/ownKeyValues", 11 | "../loopers/iota", "../loopers/iteratorObj", 12 | "../loopers/unfold", "../object", 13 | "../loopers/scanText"], 14 | function(module, unit, evalWithEnv, Pipe, interpret, arrayCompiler, 15 | array, arrayRev, sparse, sparseRev, slice, sliceRev, 16 | enumerator, values, ownKeys, ownValues, keyValues, ownKeyValues, 17 | iota, iteratorObj, unfold, object, scanText){ 18 | "use strict"; 19 | 20 | // test data 21 | 22 | var testArray = [1, 2, 3, 4, 5]; 23 | var testSparseArray = [1,,3,,5]; 24 | 25 | // tests 26 | 27 | unit.add(module, [ 28 | // test interpret 29 | function test_interpret_forEach(t){ 30 | var a = [], p = new Pipe().forEach(function(value){ a.push(value); }), 31 | x = interpret(p, testArray); 32 | eval(t.TEST("a.join(',') === '1,2,3,4,5'")); 33 | a = []; 34 | x = interpret(p, testSparseArray); 35 | eval(t.TEST("a.join(',') === '1,3,5'")); 36 | }, 37 | function test_interpret_transform(t){ 38 | var p = new Pipe().transform(function(value){ return value + 1; }), 39 | x = interpret(p, testArray.slice(0)); 40 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 41 | x = interpret(p, testSparseArray.slice(0)); 42 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 43 | }, 44 | function test_interpret_map(t){ 45 | var p = new Pipe().map(function(value){ return value + 1; }), 46 | x = interpret(p, testArray); 47 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 48 | x = interpret(p, testSparseArray); 49 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 50 | }, 51 | function test_interpret_filter(t){ 52 | var p = new Pipe().filter(function(value){ return value % 2 && value < 4; }), 53 | x = interpret(p, testArray); 54 | eval(t.TEST("x.join(',') === '1,3'")); 55 | x = interpret(p, testSparseArray); 56 | eval(t.TEST("x.join(',') === '1,3'")); 57 | }, 58 | function test_interpret_indexOf(t){ 59 | var p = new Pipe().indexOf(3), 60 | x = interpret(p, testArray); 61 | eval(t.TEST("x === 2")); 62 | x = interpret(p, testSparseArray); 63 | eval(t.TEST("x === 2")); 64 | }, 65 | function test_interpret_every(t){ 66 | var p = new Pipe().every(function(value){ return value < 6; }), 67 | x = interpret(p, testArray); 68 | eval(t.TEST("x")); 69 | x = interpret(p, testSparseArray); 70 | eval(t.TEST("x")); 71 | // 72 | p = new Pipe().every(function(value){ return value < 4; }); 73 | x = interpret(p, testArray); 74 | eval(t.TEST("!x")); 75 | x = interpret(p, testSparseArray); 76 | eval(t.TEST("!x")); 77 | }, 78 | function test_interpret_some(t){ 79 | var p = new Pipe().some(function(value){ return value % 2 && value < 4; }), 80 | x = interpret(p, testArray); 81 | eval(t.TEST("x")); 82 | x = interpret(p, testSparseArray); 83 | eval(t.TEST("x")); 84 | // 85 | p = new Pipe().some(function(value){ return value === 42; }); 86 | x = interpret(p, testArray); 87 | eval(t.TEST("!x")); 88 | x = interpret(p, testSparseArray); 89 | eval(t.TEST("!x")); 90 | }, 91 | function test_interpret_fold(t){ 92 | var p = new Pipe().fold(function(acc, value){ return acc + value; }, 0), 93 | x = interpret(p, testArray); 94 | eval(t.TEST("x === 15")); 95 | x = interpret(p, testSparseArray); 96 | eval(t.TEST("x === 9")); 97 | // 98 | p = new Pipe().fold(function(acc, value){ return acc * value; }, 1); 99 | x = interpret(p, testArray); 100 | eval(t.TEST("x === 120")); 101 | x = interpret(p, testSparseArray); 102 | eval(t.TEST("x === 15")); 103 | }, 104 | function test_interpret_scan(t){ 105 | var p = new Pipe().scan(function(acc, value){ return acc + value; }, 0), 106 | x = interpret(p, testArray); 107 | eval(t.TEST("x.join(',') === '1,3,6,10,15'")); 108 | x = interpret(p, testSparseArray); 109 | eval(t.TEST("x.join(',') === '1,,4,,9'")); 110 | // 111 | p = new Pipe().scan(function(acc, value){ return acc * value; }, 1); 112 | x = interpret(p, testArray); 113 | eval(t.TEST("x.join(',') === '1,2,6,24,120'")); 114 | x = interpret(p, testSparseArray); 115 | eval(t.TEST("x.join(',') === '1,,3,,15'")); 116 | }, 117 | function test_interpret_skip(t){ 118 | var p = new Pipe().skip(3), 119 | x = interpret(p, testArray); 120 | eval(t.TEST("x.join(',') === '4,5'")); 121 | x = interpret(p, testSparseArray); 122 | eval(t.TEST("x.join(',') === '5'")); 123 | }, 124 | function test_interpret_take(t){ 125 | var p = new Pipe().take(3), 126 | x = interpret(p, testArray); 127 | eval(t.TEST("x.join(',') === '1,2,3'")); 128 | x = interpret(p, testSparseArray); 129 | eval(t.TEST("x.join(',') === '1,3'")); 130 | }, 131 | function test_interpret_skipWhile(t){ 132 | var p = new Pipe().skipWhile(function(value){ return value % 2; }), 133 | x = interpret(p, testArray); 134 | eval(t.TEST("x.join(',') === '2,3,4,5'")); 135 | x = interpret(p, testSparseArray); 136 | eval(t.TEST("x.join(',') === ''")); 137 | // 138 | p = new Pipe().skipWhile(function(value){ return value !== 3; }); 139 | x = interpret(p, testArray); 140 | eval(t.TEST("x.join(',') === '3,4,5'")); 141 | x = interpret(p, testSparseArray); 142 | eval(t.TEST("x.join(',') === '3,5'")); 143 | }, 144 | function test_interpret_takeWhile(t){ 145 | var p = new Pipe().takeWhile(function(value){ return value % 2; }), 146 | x = interpret(p, testArray); 147 | eval(t.TEST("x.join(',') === '1'")); 148 | x = interpret(p, testSparseArray); 149 | eval(t.TEST("x.join(',') === '1,3,5'")); 150 | // 151 | p = new Pipe().takeWhile(function(value){ return value !== 3; }); 152 | x = interpret(p, testArray); 153 | eval(t.TEST("x.join(',') === '1,2'")); 154 | x = interpret(p, testSparseArray); 155 | eval(t.TEST("x.join(',') === '1'")); 156 | }, 157 | function test_interpret_voidResult(t){ 158 | var p = new Pipe().voidResult(), 159 | x = interpret(p, testArray); 160 | eval(t.TEST("x === undefined")); 161 | x = interpret(p, testSparseArray); 162 | eval(t.TEST("x === undefined")); 163 | }, 164 | function test_interpret_find(t){ 165 | if(testArray.find){ 166 | var p = new Pipe().find(function(value){ return value > 1 && value % 2; }), 167 | x = interpret(p, testArray); 168 | eval(t.TEST("x === 3")); 169 | x = interpret(p, testSparseArray); 170 | eval(t.TEST("x === 3")); 171 | } 172 | }, 173 | function test_interpret_findIndex(t){ 174 | if(testArray.find){ 175 | var p = new Pipe().findIndex(function(value){ return value > 1 && value % 2; }), 176 | x = interpret(p, testArray); 177 | eval(t.TEST("x === 2")); 178 | x = interpret(p, testSparseArray); 179 | eval(t.TEST("x === 2")); 180 | } 181 | }, 182 | function test_interpret_complex(t){ 183 | var p = new Pipe(). 184 | take(4). 185 | filter(function(_, index){ return index % 2 == 0; }). 186 | filter(function(value){ return value % 2; }). 187 | map(function(value){ return 2 * value; }). 188 | fold(function(acc, value){ return acc * value; }, 1), 189 | x = interpret(p, testArray); 190 | eval(t.TEST("x === 12")); 191 | x = interpret(p, testSparseArray); 192 | eval(t.TEST("x === 2")); 193 | }, 194 | function test_interpret_curry(t){ 195 | var p = new Pipe(). 196 | take(4). 197 | filter(function(_, index){ return index % 2 == 0; }). 198 | filter(function(value){ return value % 2; }). 199 | map(function(value){ return 2 * value; }). 200 | fold(function(acc, value){ return acc * value; }, 1), 201 | f = interpret.curry(p), 202 | x = f(testArray); 203 | eval(t.TEST("x === 12")); 204 | x = f(testSparseArray); 205 | eval(t.TEST("x === 2")); 206 | }, 207 | // test arrayCompiler 208 | function test_arrayCompiler_forEach(t){ 209 | var a = [], p = new Pipe().forEach(function(value){ a.push(value); }), 210 | f = arrayCompiler(p).compile(), x = f(testArray); 211 | eval(t.TEST("a.join(',') === '1,2,3,4,5'")); 212 | a = []; 213 | x = f(testSparseArray); 214 | eval(t.TEST("a.join(',') === '1,3,5'")); 215 | // 216 | p = new Pipe().forEach("a.push(value);"); 217 | a = []; 218 | var env = evalWithEnv({a: a}, "a"); 219 | f = arrayCompiler(p).compile(env); 220 | x = f(testArray); 221 | eval(t.TEST("a.join(',') === '1,2,3,4,5'")); 222 | env.closure.setA([]); 223 | x = f(testSparseArray); 224 | a = env.closure.getA(); 225 | eval(t.TEST("a.join(',') === '1,3,5'")); 226 | }, 227 | function test_arrayCompiler_transform(t){ 228 | var p = new Pipe().transform(function(value){ return value + 1; }), 229 | f = arrayCompiler(p).compile(), x = f(testArray.slice(0)); 230 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 231 | x = f(testSparseArray.slice(0)); 232 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 233 | // 234 | p = new Pipe().transform("value = value + 1;"); 235 | f = arrayCompiler(p).compile(); 236 | x = f(testArray.slice(0)); 237 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 238 | x = f(testSparseArray.slice(0)); 239 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 240 | }, 241 | function test_arrayCompiler_map(t){ 242 | var p = new Pipe().map(function(value){ return value + 1; }), 243 | f = arrayCompiler(p).compile(), x = f(testArray); 244 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 245 | x = f(testSparseArray); 246 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 247 | // 248 | p = new Pipe().map("++value;"); 249 | f = arrayCompiler(p).compile(); 250 | x = f(testArray); 251 | eval(t.TEST("x.join(',') === '2,3,4,5,6'")); 252 | x = f(testSparseArray); 253 | eval(t.TEST("x.join(',') === '2,,4,,6'")); 254 | }, 255 | function test_arrayCompiler_filter(t){ 256 | var p = new Pipe().filter(function(value){ return value % 2 && value < 4; }), 257 | f = arrayCompiler(p).compile(), x = f(testArray); 258 | eval(t.TEST("x.join(',') === '1,3'")); 259 | x = f(testSparseArray); 260 | eval(t.TEST("x.join(',') === '1,3'")); 261 | // 262 | p = new Pipe().filter("value % 2 && value < 4"); 263 | f = arrayCompiler(p).compile(); 264 | x = f(testArray); 265 | eval(t.TEST("x.join(',') === '1,3'")); 266 | x = f(testSparseArray); 267 | eval(t.TEST("x.join(',') === '1,3'")); 268 | }, 269 | function test_arrayCompiler_indexOf(t){ 270 | var p = new Pipe().indexOf(3), 271 | f = arrayCompiler(p, "/g/test.js").compile(), 272 | x = f(testArray); 273 | eval(t.TEST("x === 2")); 274 | x = f(testSparseArray); 275 | eval(t.TEST("x === 2")); 276 | // 277 | p = new Pipe().indexOf(Pipe.arg("item")); 278 | f = arrayCompiler(p).compile(); 279 | x = f(testArray, 5); 280 | eval(t.TEST("x === 4")); 281 | x = f(testSparseArray, 5); 282 | eval(t.TEST("x === 4")); 283 | }, 284 | function test_arrayCompiler_every(t){ 285 | var p = new Pipe().every(function(value){ return value < 6; }), 286 | f = arrayCompiler(p).compile(), x = f(testArray); 287 | eval(t.TEST("x")); 288 | x = f(testSparseArray); 289 | eval(t.TEST("x")); 290 | // 291 | p = new Pipe().every(function(value){ return value < 4; }); 292 | f = arrayCompiler(p).compile(); 293 | x = f(testArray); 294 | eval(t.TEST("!x")); 295 | x = f(testSparseArray); 296 | eval(t.TEST("!x")); 297 | // 298 | p = new Pipe().every("value < 6"); 299 | f = arrayCompiler(p).compile(); 300 | x = f(testArray); 301 | eval(t.TEST("x")); 302 | x = f(testSparseArray); 303 | eval(t.TEST("x")); 304 | // 305 | p = new Pipe().every("value < 4"); 306 | f = arrayCompiler(p).compile(); 307 | x = f(testArray); 308 | eval(t.TEST("!x")); 309 | x = f(testSparseArray); 310 | eval(t.TEST("!x")); 311 | }, 312 | function test_arrayCompiler_some(t){ 313 | var p = new Pipe().some(function(value){ return value % 2 && value < 4; }), 314 | f = arrayCompiler(p).compile(), x = f(testArray); 315 | eval(t.TEST("x")); 316 | x = f(testSparseArray); 317 | eval(t.TEST("x")); 318 | // 319 | p = new Pipe().some(function(value){ return value === 42; }); 320 | f = arrayCompiler(p).compile(); 321 | x = f(testArray); 322 | eval(t.TEST("!x")); 323 | x = f(testSparseArray); 324 | eval(t.TEST("!x")); 325 | // 326 | p = new Pipe().some("value % 2 && value < 4"); 327 | f = arrayCompiler(p).compile(); 328 | x = f(testArray); 329 | eval(t.TEST("x")); 330 | x = f(testSparseArray); 331 | eval(t.TEST("x")); 332 | // 333 | p = new Pipe().some("value === 42"); 334 | f = arrayCompiler(p).compile(); 335 | x = f(testArray); 336 | eval(t.TEST("!x")); 337 | x = f(testSparseArray); 338 | eval(t.TEST("!x")); 339 | }, 340 | function test_arrayCompiler_fold(t){ 341 | var p = new Pipe().fold(function(acc, value){ return acc + value; }, 0), 342 | f = arrayCompiler(p).compile(), 343 | x = f(testArray); 344 | eval(t.TEST("x === 15")); 345 | x = f(testSparseArray); 346 | eval(t.TEST("x === 9")); 347 | // 348 | p = new Pipe().fold(function(acc, value){ return acc * value; }, 1); 349 | f = arrayCompiler(p).compile(); 350 | x = f(testArray); 351 | eval(t.TEST("x === 120")); 352 | x = f(testSparseArray); 353 | eval(t.TEST("x === 15")); 354 | // 355 | p = new Pipe().fold("accumulator += value;", Pipe.arg("acc")); 356 | f = arrayCompiler(p).compile(); 357 | x = f(testArray, 0); 358 | eval(t.TEST("x === 15")); 359 | x = f(testSparseArray, 0); 360 | eval(t.TEST("x === 9")); 361 | // 362 | p = new Pipe().fold("accumulator *= value;", Pipe.arg("acc")); 363 | f = arrayCompiler(p).compile(); 364 | x = f(testArray, 1); 365 | eval(t.TEST("x === 120")); 366 | x = f(testSparseArray, 1); 367 | eval(t.TEST("x === 15")); 368 | }, 369 | function test_arrayCompiler_scan(t){ 370 | var p = new Pipe().scan(function(acc, value){ return acc + value; }, 0), 371 | f = arrayCompiler(p).compile(), 372 | x = f(testArray); 373 | eval(t.TEST("x.join(',') === '1,3,6,10,15'")); 374 | x = f(testSparseArray); 375 | eval(t.TEST("x.join(',') === '1,,4,,9'")); 376 | // 377 | p = new Pipe().scan(function(acc, value){ return acc * value; }, 1); 378 | f = arrayCompiler(p).compile(); 379 | x = f(testArray); 380 | eval(t.TEST("x.join(',') === '1,2,6,24,120'")); 381 | x = f(testSparseArray); 382 | eval(t.TEST("x.join(',') === '1,,3,,15'")); 383 | // 384 | p = new Pipe().scan("accumulator += value;", Pipe.arg("acc")); 385 | f = arrayCompiler(p).compile(); 386 | x = f(testArray, 0); 387 | eval(t.TEST("x.join(',') === '1,3,6,10,15'")); 388 | x = f(testSparseArray, 0); 389 | eval(t.TEST("x.join(',') === '1,,4,,9'")); 390 | // 391 | p = new Pipe().scan("accumulator *= value;", Pipe.arg("acc")); 392 | f = arrayCompiler(p).compile(); 393 | x = f(testArray, 1); 394 | eval(t.TEST("x.join(',') === '1,2,6,24,120'")); 395 | x = f(testSparseArray, 1); 396 | eval(t.TEST("x.join(',') === '1,,3,,15'")); 397 | }, 398 | function test_arrayCompiler_skip(t){ 399 | var p = new Pipe().skip(3), 400 | f = arrayCompiler(p).compile(), 401 | x = f(testArray); 402 | eval(t.TEST("x.join(',') === '4,5'")); 403 | x = f(testSparseArray); 404 | eval(t.TEST("x.join(',') === '5'")); 405 | // 406 | p = new Pipe().skip(Pipe.arg("num")); 407 | f = arrayCompiler(p).compile(); 408 | x = f(testArray, 3); 409 | eval(t.TEST("x.join(',') === '4,5'")); 410 | x = f(testSparseArray, 3); 411 | eval(t.TEST("x.join(',') === '5'")); 412 | }, 413 | function test_arrayCompiler_take(t){ 414 | var p = new Pipe().take(3), 415 | f = arrayCompiler(p).compile(), 416 | x = f(testArray); 417 | eval(t.TEST("x.join(',') === '1,2,3'")); 418 | x = f(testSparseArray); 419 | eval(t.TEST("x.join(',') === '1,3'")); 420 | // 421 | p = new Pipe().take(Pipe.arg("num")); 422 | f = arrayCompiler(p).compile(); 423 | x = f(testArray, 3); 424 | eval(t.TEST("x.join(',') === '1,2,3'")); 425 | x = f(testSparseArray, 3); 426 | eval(t.TEST("x.join(',') === '1,3'")); 427 | }, 428 | function test_arrayCompiler_skipWhile(t){ 429 | var p = new Pipe().skipWhile(function(value){ return value % 2; }), 430 | f = arrayCompiler(p).compile(), x = f(testArray); 431 | eval(t.TEST("x.join(',') === '2,3,4,5'")); 432 | x = f(testSparseArray); 433 | eval(t.TEST("x.join(',') === ''")); 434 | // 435 | p = new Pipe().skipWhile(function(value){ return value !== 3; }); 436 | f = arrayCompiler(p).compile(); 437 | x = f(testArray); 438 | eval(t.TEST("x.join(',') === '3,4,5'")); 439 | x = f(testSparseArray); 440 | eval(t.TEST("x.join(',') === '3,5'")); 441 | // 442 | }, 443 | function test_arrayCompiler_takeWhile(t){ 444 | var p = new Pipe().takeWhile(function(value){ return value % 2; }), 445 | f = arrayCompiler(p).compile(), x = f(testArray); 446 | eval(t.TEST("x.join(',') === '1'")); 447 | x = f(testSparseArray); 448 | eval(t.TEST("x.join(',') === '1,3,5'")); 449 | // 450 | p = new Pipe().takeWhile(function(value){ return value !== 3; }); 451 | f = arrayCompiler(p).compile(); 452 | x = f(testArray); 453 | eval(t.TEST("x.join(',') === '1,2'")); 454 | x = f(testSparseArray); 455 | eval(t.TEST("x.join(',') === '1'")); 456 | // 457 | }, 458 | function test_arrayCompiler_voidResult(t){ 459 | var p = new Pipe().voidResult(), 460 | f = arrayCompiler(p).compile(), 461 | x = f(testArray); 462 | eval(t.TEST("x === undefined")); 463 | x = f(testSparseArray); 464 | eval(t.TEST("x === undefined")); 465 | }, 466 | function test_arrayCompiler_find(t){ 467 | if(testArray.find){ 468 | var p = new Pipe().find(function(value){ return value > 1 && value % 2; }), 469 | f = arrayCompiler(p).compile(), 470 | x = f(testArray); 471 | eval(t.TEST("x === 3")); 472 | x = f(testSparseArray); 473 | eval(t.TEST("x === 3")); 474 | } 475 | }, 476 | function test_arrayCompiler_findIndex(t){ 477 | if(testArray.find){ 478 | var p = new Pipe().findIndex(function(value){ return value > 1 && value % 2; }), 479 | f = arrayCompiler(p).compile(), 480 | x = f(testArray); 481 | eval(t.TEST("x === 2")); 482 | x = f(testSparseArray); 483 | eval(t.TEST("x === 2")); 484 | } 485 | }, 486 | function test_arrayCompiler_complex(t){ 487 | var p = new Pipe(). 488 | take(4). 489 | filter(function(_, index){ return index % 2 == 0; }). 490 | filter(function(value){ return value % 2; }). 491 | map(function(value){ return 2 * value; }). 492 | fold(function(acc, value){ return acc * value; }, 1), 493 | f = arrayCompiler(p).compile(), 494 | x = f(testArray); 495 | eval(t.TEST("x === 12")); 496 | x = f(testSparseArray); 497 | eval(t.TEST("x === 2")); 498 | // 499 | p = new Pipe(). 500 | take(Pipe.arg("take")). 501 | filter(function(_, index){ return index % 2 == 0; }). 502 | filter("value % 2"). 503 | map(function(value){ return 2 * value; }). 504 | fold("accumulator = accumulator * value;", 1); 505 | f = arrayCompiler(p).compile(); 506 | x = f(testArray, 4); 507 | eval(t.TEST("x === 12")); 508 | x = f(testSparseArray, 4); 509 | eval(t.TEST("x === 2")); 510 | // 511 | p = new Pipe(). 512 | take(Pipe.arg("take")). 513 | filter("index % 2 == 0"). 514 | filter("value % 2"). 515 | map("value = 2 * value;"). 516 | fold("accumulator = accumulator * value;", Pipe.arg("acc")); 517 | f = arrayCompiler(p).compile(); 518 | x = f(testArray, 4, 1); 519 | eval(t.TEST("x === 12")); 520 | x = f(testSparseArray, 4, 1); 521 | eval(t.TEST("x === 2")); 522 | }, 523 | // test array 524 | function test_array(t){ 525 | var sum = new Pipe(). 526 | fold(function(acc, value){ return acc + value; }, 0), 527 | norm = new Pipe(). 528 | add("decl", {args: ["total"]}). 529 | map("value /= total;"). 530 | map("value = Math.round(value * 100);"), 531 | fSum = array(sum).compile(), 532 | fNorm = array(norm).compile(), 533 | percent = function(source){ 534 | return fNorm(source, fSum(source)); 535 | }, 536 | result = percent(testArray); 537 | eval(t.TEST("result.join(',') === '7,13,20,27,33'")); 538 | fNorm = array(norm, "name2", true).compile(); 539 | result = [0]; 540 | fNorm(testArray, result, fSum(testArray)); 541 | eval(t.TEST("result.join(',') === '0,7,13,20,27,33'")); 542 | }, 543 | // test a reversed array 544 | function test_reversed_array(t){ 545 | var p = new Pipe().fold(function(acc, value){ acc.push(value); return acc; }, []); 546 | var f = arrayRev(p).compile(); 547 | var r = f(testArray); 548 | eval(t.TEST("r.join(',') === '5,4,3,2,1'")); 549 | p = new Pipe().fold("accumulator.push(value);", Pipe.arg("array")); 550 | f = arrayRev(p).compile(); 551 | r = f(testArray, []); 552 | eval(t.TEST("r.join(',') === '5,4,3,2,1'")); 553 | }, 554 | // test sparse array 555 | function test_sparse(t){ 556 | var sum = new Pipe(). 557 | fold(function(acc, value){ return acc + value; }, 0), 558 | norm = new Pipe(). 559 | add("decl", {args: ["total"]}). 560 | map("value /= total;"). 561 | map("value = Math.round(value * 100);"), 562 | fSum = sparse(sum).compile(), 563 | fNorm = sparse(norm).compile(), 564 | percent = function(source){ 565 | return fNorm(source, fSum(source)); 566 | }, 567 | result = percent(testArray); 568 | eval(t.TEST("result.join(',') === '7,13,20,27,33'")); 569 | result = percent(testSparseArray); 570 | eval(t.TEST("result.join(',') === '11,33,56'")); 571 | }, 572 | // test a reversed sparse array 573 | function test_reversed_sparse(t){ 574 | var p = new Pipe().fold(function(acc, value){ acc.push(value); return acc; }, []); 575 | var f = sparseRev(p).compile(); 576 | var r = f(testSparseArray); 577 | eval(t.TEST("r.join(',') === '5,3,1'")); 578 | p = new Pipe().fold("accumulator.push(value);", Pipe.arg("array")); 579 | f = sparseRev(p).compile(); 580 | r = f(testSparseArray, []); 581 | eval(t.TEST("r.join(',') === '5,3,1'")); 582 | }, 583 | // test slice 584 | function test_slice(t){ 585 | var sum = new Pipe(). 586 | fold(function(acc, value){ return acc + value; }, 0), 587 | norm = new Pipe(). 588 | add("decl", {args: ["total"]}). 589 | map("value /= total;"). 590 | map("value = Math.round(value * 100);"), 591 | fSum = slice(sum).compile(), 592 | fNorm = slice(norm).compile(), 593 | percent = function(source, from, to){ 594 | return fNorm(source, from, to, fSum(source, from, to)); 595 | }, 596 | result = percent(testArray, 1, -1); 597 | eval(t.TEST("result.join(',') === '22,33,44'")); 598 | fNorm = slice(norm, null, true).compile(); 599 | result = [0]; 600 | fNorm(testArray, 1, -1, result, fSum(testArray, 1, -1)); 601 | eval(t.TEST("result.join(',') === '0,22,33,44'")); 602 | }, 603 | // test a reversed slice 604 | function test_reversed_slice(t){ 605 | var p = new Pipe().fold(function(acc, value){ acc.push(value); return acc; }, []); 606 | var f = sliceRev(p).compile(); 607 | var r = f(testArray, -1, 1); 608 | eval(t.TEST("r.join(',') === '4,3,2'")); 609 | p = new Pipe().fold("accumulator.push(value);", Pipe.arg("array")); 610 | f = sliceRev(p).compile(); 611 | r = f(testArray, -1, 1, [0]); 612 | eval(t.TEST("r.join(',') === '0,4,3,2'")); 613 | }, 614 | // test enumerator 615 | function test_enumerator_over_keys(t){ 616 | var p = new Pipe(); 617 | var f = enumerator(p).compile(); 618 | var x = {b: 2, d: 3}; 619 | var r = f(x); 620 | eval(t.TEST("r.sort().join(',') === 'b,d'")); 621 | var Y = function(){}; 622 | Y.prototype = x; 623 | var y = new Y(); 624 | y.a = 1; 625 | y.c = 2; 626 | y.e = 3; 627 | r = f(y); 628 | eval(t.TEST("r.sort().join(',') === 'a,b,c,d,e'")); 629 | }, 630 | function test_enumerator_over_iterator(t){ 631 | if(typeof Iterator != "undefined" && typeof StopIteration != "undefined"){ 632 | var p = new Pipe(); 633 | var f = enumerator(p).compile(); 634 | var r = f(Iterator({a: 1, b: 2, c: 3}, true)); 635 | eval(t.TEST("r.sort().join(',') === 'a,b,c'")); 636 | } 637 | }, 638 | function test_enumerator_over_keys_with_iterator(t){ 639 | if(typeof Iterator != "undefined" && typeof StopIteration != "undefined"){ 640 | var p = new Pipe(); 641 | var f = enumerator(p).compile(); 642 | var r = f(Iterator({a: 1, b: 2, c: 3}, true)); 643 | eval(t.TEST("r.sort().join(',') === 'a,b,c'")); 644 | } 645 | }, 646 | function test_enumerator_over_pairs_with_iterator(t){ 647 | if(typeof Iterator != "undefined" && typeof StopIteration != "undefined"){ 648 | var p = new Pipe().add("decl", {args: "idx"}).map("value = value[idx];"); 649 | var f = enumerator(p).compile(); 650 | var r = f(Iterator({a: 1, b: 2, c: 3}), 0); 651 | eval(t.TEST("r.sort().join(',') === 'a,b,c'")); 652 | r = f(Iterator({a: 1, b: 2, c: 3}), 1); 653 | eval(t.TEST("r.sort().join(',') === '1,2,3'")); 654 | } 655 | }, 656 | function test_enumerator_with_custom_iterator(t){ 657 | if(typeof Iterator != "undefined" && typeof StopIteration != "undefined"){ 658 | // custom iterator: unbounded Fibonacci sequence 659 | var FibIter = function(){ 660 | this.pp = this.p = 0; 661 | }; 662 | FibIter.prototype.next = function(){ 663 | var c = (this.p + this.pp) || 1; 664 | this.pp = this.p; 665 | this.p = c; 666 | return c; 667 | }; 668 | var y = { 669 | __iterator__: function(){ 670 | // Endless Fibonacci numbers 671 | return new FibIter(); 672 | } 673 | }; 674 | 675 | var p = new Pipe().takeWhile("value < 10"); 676 | var f = enumerator(p).compile(); 677 | var r = f(y); 678 | eval(t.TEST("r.join(',') === '1,1,2,3,5,8'")); 679 | } 680 | }, 681 | function test_enumerator_with_generator(t){ 682 | if(typeof Iterator != "undefined" && typeof StopIteration != "undefined"){ 683 | // custom generator: unbounded Fibonacci sequence 684 | var x = { 685 | // eval is here to hide "yield" from non-compliant interpreters 686 | __iterator__: eval([ 687 | "(function(){", 688 | " var pp = 1, p = 1;", 689 | " yield pp;", 690 | " yield p;", 691 | " for(;;){", 692 | " var c = pp + p;", 693 | " yield c;", 694 | " pp = p;", 695 | " p = c;", 696 | " }", 697 | "})" 698 | ].join("\n")) 699 | }; 700 | 701 | var p = new Pipe().takeWhile("value < 10"); 702 | var f = enumerator(p).compile(); 703 | var r = f(x); 704 | eval(t.TEST("r.join(',') === '1,1,2,3,5,8'")); 705 | } 706 | }, 707 | // test values 708 | function test_values(t){ 709 | var p = new Pipe(); 710 | var f = values(p).compile(); 711 | var x = {b: 4, d: 5}; 712 | var r = f(x); 713 | eval(t.TEST("r.sort().join(',') === '4,5'")); 714 | var Y = function(){}; 715 | Y.prototype = x; 716 | var y = new Y(); 717 | y.a = 1; 718 | y.c = 2; 719 | y.e = 3; 720 | r = f(y); 721 | eval(t.TEST("r.sort().join(',') === '1,2,3,4,5'")); 722 | }, 723 | // test ownKeys 724 | function test_ownKeys(t){ 725 | var p = new Pipe(); 726 | var f = ownKeys(p).compile(); 727 | var x = {b: 4, d: 5}; 728 | var r = f(x); 729 | eval(t.TEST("r.sort().join(',') === 'b,d'")); 730 | var Y = function(){}; 731 | Y.prototype = x; 732 | var y = new Y(); 733 | y.a = 1; 734 | y.c = 2; 735 | y.e = 3; 736 | r = f(y); 737 | eval(t.TEST("r.sort().join(',') === 'a,c,e'")); 738 | }, 739 | // test ownValues 740 | function test_ownValues(t){ 741 | var p = new Pipe(); 742 | var f = ownValues(p).compile(); 743 | var x = {b: 4, d: 5}; 744 | var r = f(x); 745 | eval(t.TEST("r.sort().join(',') === '4,5'")); 746 | var Y = function(){}; 747 | Y.prototype = x; 748 | var y = new Y(); 749 | y.a = 1; 750 | y.c = 2; 751 | y.e = 3; 752 | r = f(y); 753 | eval(t.TEST("r.sort().join(',') === '1,2,3'")); 754 | }, 755 | // test keyValues 756 | function test_keyValues(t){ 757 | var p = new Pipe().map("value = value[0] + value[1];"); 758 | var f = keyValues(p).compile(); 759 | var x = {b: 4, d: 5}; 760 | var r = f(x); 761 | eval(t.TEST("r.sort().join(',') === 'b4,d5'")); 762 | var Y = function(){}; 763 | Y.prototype = x; 764 | var y = new Y(); 765 | y.a = 1; 766 | y.c = 2; 767 | y.e = 3; 768 | r = f(y); 769 | eval(t.TEST("r.sort().join(',') === 'a1,b4,c2,d5,e3'")); 770 | }, 771 | // test ownKeyValues 772 | function test_ownKeyValues(t){ 773 | var p = new Pipe().map("value = value[0] + value[1];"); 774 | var f = ownKeyValues(p).compile(); 775 | var x = {b: 4, d: 5}; 776 | var r = f(x); 777 | eval(t.TEST("r.sort().join(',') === 'b4,d5'")); 778 | var Y = function(){}; 779 | Y.prototype = x; 780 | var y = new Y(); 781 | y.a = 1; 782 | y.c = 2; 783 | y.e = 3; 784 | r = f(y); 785 | eval(t.TEST("r.sort().join(',') === 'a1,c2,e3'")); 786 | }, 787 | // test iota 788 | function test_iota(t){ 789 | var p = new Pipe(); 790 | var f = iota(p).compile(); 791 | var r = f(0, 5); 792 | eval(t.TEST("r.join(',') === '0,1,2,3,4'")); 793 | r = f(1, 5, 2); 794 | eval(t.TEST("r.join(',') === '1,3'")); 795 | r = f(1, -1); 796 | eval(t.TEST("r.join(',') === '1,0'")); 797 | p = new Pipe().take(Pipe.arg("num")); 798 | f = iota(p).compile(); 799 | r = f(1, -1, 0.25, 5); 800 | eval(t.TEST("r.join(',') === '1,0.75,0.5,0.25,0'")); 801 | }, 802 | // test iteratorObj 803 | function test_iteratorObj(t){ 804 | // custom iterator: unbounded Fibonacci sequence 805 | var FibIter = function(){ 806 | this.pp = 0; 807 | this.p = 0; 808 | }; 809 | FibIter.prototype.hasNext = function(){ return true; }; 810 | FibIter.prototype.next = function(){ 811 | var c = (this.p + this.pp) || 1; 812 | this.pp = this.p; 813 | this.p = c; 814 | return c; 815 | }; 816 | var y = new FibIter(); 817 | 818 | var p = new Pipe().takeWhile("value < 10"); 819 | var f = iteratorObj(p).compile(); 820 | var r = f(y); 821 | eval(t.TEST("r.join(',') === '1,1,2,3,5,8'")); 822 | }, 823 | // test unfold 824 | function test_unfold(t){ 825 | var p = new Pipe(); 826 | var f = unfold( 827 | "accumulator < 100", // pred 828 | "value = accumulator;", // value 829 | "accumulator *= 2;" // next 830 | )(p).compile(); 831 | var r = f(1); 832 | eval(t.TEST("r.join(',') === '1,2,4,8,16,32,64'")); 833 | }, 834 | // test an object 835 | function test_object(t){ 836 | var sum = new Pipe(). 837 | fold(function(acc, value){ return acc + value; }, 0), 838 | norm = new Pipe(). 839 | add("decl", {args: ["total"]}). 840 | map("value /= total;"). 841 | map("value = Math.round(value * 100);"), 842 | fSum = object(sum).compile(), 843 | fNorm = object(norm).compile(), 844 | percent = function(source){ 845 | var r = []; 846 | fSum.start(); 847 | fNorm.start(15); 848 | for(var i = 0; i < testArray.length; ++i){ 849 | fSum.process(testArray[i]); 850 | r.push(fNorm.process(testArray[i])); 851 | } 852 | fSum.stop(); 853 | fNorm.stop(); 854 | eval(t.TEST("fSum.getResult() == 15")); 855 | return r; 856 | }, 857 | result = percent(testArray); 858 | eval(t.TEST("result.join(',') === '7,13,20,27,33'")); 859 | }, 860 | // test find() 861 | function test_find(t){ 862 | var p = new Pipe().find("value > 1 && value % 2"), 863 | f = array(p).compile(), 864 | x = f(testArray); 865 | eval(t.TEST("x === 3")); 866 | x = f([2,4,6]); 867 | eval(t.TEST("x === undefined")); 868 | }, 869 | // test findIndex() 870 | function test_findIndex(t){ 871 | var p = new Pipe().findIndex("value > 1 && value % 2"), 872 | f = array(p).compile(), 873 | x = f(testArray); 874 | eval(t.TEST("x === 2")); 875 | x = f([2,4,6]); 876 | eval(t.TEST("x === -1")); 877 | }, 878 | // text a text scan 879 | function test_scanText(t){ 880 | var p = new Pipe(). 881 | take(Pipe.arg("take")). 882 | filter("index % 2 == 0"). 883 | map("value = +value;"). 884 | filter("value % 2"). 885 | map("value = 2 * value;"). 886 | fold("accumulator = accumulator * value;", Pipe.arg("acc")), 887 | f = scanText(p).compile(), 888 | x = f("1,2,3,4,5,6", /\d+/g, 0, 4, 1); 889 | eval(t.TEST("x === 12")); 890 | 891 | p = new Pipe().map("value = +value;").find("value > 1 && value % 2"); 892 | f = scanText(p).compile(); 893 | x = f("1,2,3,4,5,6", /\d+/g); 894 | eval(t.TEST("x === 3")); 895 | x = f("2,4,6", /\d+/g); 896 | eval(t.TEST("x === undefined")); 897 | 898 | p = new Pipe().map("value = +value;").findIndex("value > 1 && value % 2"); 899 | f = scanText(p).compile(); 900 | x = f("1,2,3,4,5,6", /\d+/g); 901 | eval(t.TEST("x === 2")); 902 | x = f("2,4,6", /\d+/g); 903 | eval(t.TEST("x === -1")); 904 | } 905 | ]); 906 | 907 | unit.run(); 908 | }); 909 | --------------------------------------------------------------------------------