├── .gitignore ├── AUTHORS ├── tests ├── tests.js ├── tests.html ├── test_algos_quickSort.js ├── phantom.js ├── test_algos_mergeArrays.js ├── test_algos_binarySearch.js ├── test_algos_heap.js └── test_main.js ├── .travis.yml ├── replace.js ├── count.js ├── package.json ├── Target.js ├── README.md ├── main.js ├── jst.js ├── Pool.js ├── evalWithEnv.js ├── algos ├── mergeArrays.js ├── heap │ ├── push.js │ ├── pop.js │ ├── make.js │ └── sort.js ├── binarySearch.js └── quickSort.js ├── lambda.js └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | *.iml 3 | .idea 4 | *.sublime-* 5 | report/* 6 | coverage/* 7 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Eugene Lazutkin (http://lazutkin.com/) 2 | Max Motovilov 3 | -------------------------------------------------------------------------------- /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 | (["heya-unit", "./test_main", "./test_algos_binarySearch", "./test_algos_quickSort", "./test_algos_mergeArrays", 3 | "./test_algos_heap"], 4 | function(unit){ 5 | "use strict"; 6 | 7 | unit.run(); 8 | 9 | return {}; 10 | }); 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.10" 5 | - "0.12" 6 | - "iojs" 7 | 8 | env: 9 | - PHANTOM=true 10 | - PHANTOM=false 11 | 12 | matrix: 13 | exclude: 14 | - node_js: "0.10" 15 | env: PHANTOM=true 16 | - node_js: "iojs" 17 | env: PHANTOM=true 18 | 19 | before_script: if [ "$PHANTOM" == "true" ]; then export RUN_TEST="phantomjs tests/phantom.js"; else export RUN_TEST="npm test"; fi 20 | 21 | script: $RUN_TEST 22 | -------------------------------------------------------------------------------- /replace.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 | return function replace(tmpl, dict){ 5 | return tmpl.replace(/\$+\{([^\}\s\r\n]+)\}/g, function(match, name){ 6 | if(match.length - name.length > 3){ 7 | return match.substring(1); 8 | } 9 | return dict[name]; 10 | }); 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /count.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 | return function count(tmpl, dict){ 5 | dict = dict || {}; 6 | tmpl.replace(/\$+\{([^\}\s\r\n]+)\}/g, function(match, name){ 7 | if(match.length - name.length == 3){ 8 | if(dict.hasOwnProperty(name)){ 9 | ++dict[name]; 10 | }else{ 11 | dict[name] = 1; 12 | } 13 | } 14 | return ""; 15 | }); 16 | return dict; 17 | }; 18 | }); 19 | -------------------------------------------------------------------------------- /tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | heya-ctr test runner 5 | 6 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heya-ctr", 3 | "version": "0.2.3", 4 | "description": "Constructor: a toolkit to construct JavaScript code.", 5 | "main": "main.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "heya-unify": ">=0.1", 12 | "heya-unit": ">=0.1" 13 | }, 14 | "scripts": { 15 | "test": "node tests/tests.js" 16 | }, 17 | "amd": {}, 18 | "volo": { 19 | "type": "directory" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/heya/ctr.git" 24 | }, 25 | "keywords": [ 26 | "code generation", 27 | "code construction", 28 | "templating", 29 | "templates", 30 | "template" 31 | ], 32 | "author": "Eugene Lazutkin (http://lazutkin.com/)", 33 | "license": "BSD" 34 | } 35 | -------------------------------------------------------------------------------- /Target.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 | (["./evalWithEnv"], function(evalWithEnv){ 3 | "use strict"; 4 | 5 | function Target(lines, props){ 6 | this.lines = lines; 7 | this.props = props; 8 | } 9 | 10 | Target.prototype = { 11 | getCode: function(){ 12 | return this.lines.join("\n"); 13 | }, 14 | compile: function(env){ 15 | var code = this.getCode(); 16 | if(env){ 17 | if(typeof env != "function"){ 18 | env = evalWithEnv(env); 19 | } 20 | code = env(code); 21 | }else{ 22 | code = eval(code); 23 | } 24 | if(code && this.props){ 25 | for(var key in this.props){ 26 | code[key] = this.props[key]; 27 | } 28 | } 29 | return code; 30 | } 31 | }; 32 | 33 | return Target; 34 | }); 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Constructor 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 | Constructor: a toolkit to construct JavaScript code. 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-ctr 18 | ``` 19 | 20 | For your browser-based projects I suggest to use [volo.js](http://volojs.org): 21 | 22 | ``` 23 | volo add -amdoff heya/ctr heya-ctr 24 | ``` 25 | 26 | [npm-image]: https://img.shields.io/npm/v/heya-ctr.svg 27 | [npm-url]: https://npmjs.org/package/heya-ctr 28 | [deps-image]: https://img.shields.io/david/heya/ctr.svg 29 | [deps-url]: https://david-dm.org/heya/ctr 30 | [dev-deps-image]: https://img.shields.io/david/dev/heya/ctr.svg 31 | [dev-deps-url]: https://david-dm.org/heya/ctr#info=devDependencies 32 | [travis-image]: https://img.shields.io/travis/heya/ctr.svg 33 | [travis-url]: https://travis-ci.org/heya/ctr 34 | -------------------------------------------------------------------------------- /main.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 | (["./replace", "./Target"], function(replace, Target){ 3 | "use strict"; 4 | return function constructor(tmpl, dict, props){ 5 | tmpl = tmpl instanceof Array ? tmpl : 6 | (tmpl.getCode ? tmpl.getCode(true) : tmpl.split("\n")); 7 | var result = []; 8 | for(var i = 0, l = tmpl.length; i < l; ++i){ 9 | var line = replace(tmpl[i], dict), 10 | found = /#+\{([^\}\s\r\n]+)\}/.exec(line); 11 | if(found){ 12 | var pattern = found[0]; 13 | if(pattern.length - found[1].length > 3){ 14 | result.push(line.replace(pattern, pattern.substring(1))); 15 | continue; 16 | } 17 | var value = dict[found[1]]; 18 | if(value && value instanceof Array){ 19 | for(var j = 0, k = value.length; j < k; ++j){ 20 | result.push(line.replace(pattern, replace(value[j], dict))); 21 | } 22 | }else{ 23 | if(value !== undefined){ 24 | result.push(line.replace(pattern, replace(value, dict))); 25 | } 26 | } 27 | }else{ 28 | result.push(line); 29 | } 30 | } 31 | return new Target(result, props); 32 | }; 33 | }); 34 | -------------------------------------------------------------------------------- /tests/test_algos_quickSort.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", "heya-unify", "../algos/quickSort"], 3 | function(module, unit, unify, qsort){ 4 | "use strict"; 5 | 6 | function cmpNum(a, b){ return a - b; } 7 | 8 | unit.add(module, [ 9 | function test_random(t){ 10 | var qs = qsort("a < b").compile(); 11 | 12 | var arrays = 100, size = 100; 13 | for(var i = 0; i < arrays; ++i){ 14 | var a = new Array(size); 15 | for(var j = 0; j < size; ++j){ 16 | a[j] = Math.random(); 17 | } 18 | var b = a.slice(0); 19 | a.sort(cmpNum); 20 | qs(b); 21 | eval(t.TEST("unify(a, b)")); 22 | } 23 | }, 24 | function test_external(t){ 25 | var qs = qsort(function(a, b){ return a < b; }).compile(); 26 | 27 | var arrays = 100, size = 100; 28 | for(var i = 0; i < arrays; ++i){ 29 | var a = new Array(size); 30 | for(var j = 0; j < size; ++j){ 31 | a[j] = Math.random(); 32 | } 33 | var b = a.slice(0); 34 | a.sort(cmpNum); 35 | qs(b); 36 | eval(t.TEST("unify(a, b)")); 37 | } 38 | } 39 | ]); 40 | 41 | return {}; 42 | }); 43 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /tests/test_algos_mergeArrays.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", "heya-unify", "../algos/mergeArrays"], 3 | function(module, unit, unify, merge){ 4 | "use strict"; 5 | 6 | function cmpNum(a, b){ return a - b; } 7 | 8 | unit.add(module, [ 9 | function test_random(t){ 10 | var m = merge("a < b").compile(); 11 | 12 | var arrays = 100, size = 100; 13 | for(var i = 0; i < arrays; ++i){ 14 | var a = new Array(size); 15 | for(var j = 0; j < size; ++j){ 16 | a[j] = Math.random(); 17 | } 18 | var b = new Array(size); 19 | for(var j = 0; j < size; ++j){ 20 | b[j] = Math.random(); 21 | } 22 | var c = a.concat(b).sort(cmpNum), 23 | d = m(a.sort(cmpNum), b.sort(cmpNum)); 24 | eval(t.TEST("unify(c, d)")); 25 | } 26 | }, 27 | function test_external(t){ 28 | var m = merge(function(a, b){ return a < b; }).compile(); 29 | 30 | var arrays = 100, size = 100; 31 | for(var i = 0; i < arrays; ++i){ 32 | var a = new Array(size); 33 | for(var j = 0; j < size; ++j){ 34 | a[j] = Math.random(); 35 | } 36 | var b = new Array(size); 37 | for(var j = 0; j < size; ++j){ 38 | b[j] = Math.random(); 39 | } 40 | var c = a.concat(b).sort(cmpNum), 41 | d = m(a.sort(cmpNum), b.sort(cmpNum)); 42 | eval(t.TEST("unify(c, d)")); 43 | } 44 | } 45 | ]); 46 | 47 | return {}; 48 | }); 49 | -------------------------------------------------------------------------------- /jst.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 | (["./Target"], function(Target){ 3 | "use strict"; 4 | 5 | var escapeTable = { 6 | "\\": "\\\\", 7 | "\t": "\\t", 8 | "\r": "\\r", 9 | "\n": "\\n", 10 | "\u2028": "\\u2028", 11 | "\u2029": "\\u2029", 12 | '"': '\\"', 13 | "'": "\\'" 14 | }; 15 | 16 | function escape(text){ 17 | return text.replace(/[\\\t\r\n\u2028\u2029"']/g, function(match){ 18 | return escapeTable[match]; 19 | }); 20 | } 21 | 22 | function jst(tmpl){ 23 | tmpl = tmpl instanceof Array ? tmpl.join("\n") : 24 | (tmpl.getCode ? tmpl.getCode() : tmpl); 25 | var result = [ 26 | "(function(){", 27 | " var __r = [];", 28 | " function print(text){ __r.push(text); }" 29 | ]; 30 | var start = 0; 31 | tmpl.replace(/<%(=?)([\s\S]+?)%>/g, function(match, prefix, text, offset){ 32 | // process the previous literal 33 | if(start < offset){ 34 | result.push(" __r.push(\"" + escape(tmpl.substring(start, offset)) + "\");"); 35 | } 36 | start = offset + match.length; 37 | if(prefix){ 38 | // interpolate 39 | result.push(" __r.push(" + text + ");"); 40 | }else{ 41 | // evaluate 42 | result.push(" " + text); 43 | } 44 | return ""; 45 | }); 46 | if(start < tmpl.length){ 47 | result.push(" __r.push(\"" + escape(tmpl.substring(start)) + "\");"); 48 | } 49 | result.push( 50 | " return __r.join(\"\");", 51 | "})" 52 | ); 53 | return new Target(result); 54 | } 55 | 56 | jst.escape = escape; 57 | 58 | return jst; 59 | }); 60 | -------------------------------------------------------------------------------- /Pool.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 | // standard delegator (see Object.create() and dcl/mini.js) 6 | var F = new Function; 7 | function delegate(o){ 8 | F.prototype = o; 9 | var t = new F; 10 | F.prototype = null; 11 | return t; 12 | } 13 | 14 | // standard mixer (see dcl/mini.js) 15 | function mix(a, b){ 16 | for(var n in b){ 17 | if(b.hasOwnProperty(n)){ 18 | a[n] = b[n]; 19 | } 20 | } 21 | } 22 | 23 | function Pool(){ 24 | this.envs = []; 25 | } 26 | 27 | Pool.delegate = delegate; 28 | Pool.mix = mix; 29 | 30 | Pool.prototype = { 31 | newEnv: function(){ 32 | return this.top ? delegate(this.top) : {}; 33 | }, 34 | commit: function(env){ 35 | this.envs.push(this.top = env); 36 | }, 37 | merge: function(env){ 38 | if(!this.top){ 39 | this.envs.push(this.top = {}); 40 | } 41 | mix(this.top, env); 42 | }, 43 | getTop: function(){ 44 | return this.top; 45 | }, 46 | pop: function(){ 47 | if(this.top){ 48 | var env = this.envs.pop(); 49 | var l = this.envs.length; 50 | this.top = l ? this.envs[l - 1] : null; 51 | return env; 52 | } 53 | return null; 54 | } 55 | }; 56 | 57 | return Pool; 58 | }); 59 | 60 | // Example of a commit-based exception processing: 61 | // 62 | // var pool = new Pool(); 63 | // for(var i = 0; i < TRIES; ++i){ 64 | // try{ 65 | // var env = pool.newEnv(); 66 | // doSomethingWithEnv(env); 67 | // pool.commit(env); 68 | // break; // we are done 69 | // }catch(e){ 70 | // // error processing 71 | // } 72 | // // if we are here => retry 73 | // } 74 | -------------------------------------------------------------------------------- /evalWithEnv.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 | // The idea is by Max Motovilov. 6 | 7 | function evalWithEnv(env, accessors, binder){ 8 | // disassemble our dictionary 9 | var keys = [], vals = []; 10 | for(var key in env){ 11 | keys.push(key); 12 | vals.push(env[key]); 13 | } 14 | env = new Function(keys, "return function(){ return eval(arguments[0]); }").apply(null, vals); 15 | env.keys = keys; 16 | accessors && evalWithEnv.addAccessors(env, accessors, binder); 17 | return env; 18 | } 19 | 20 | function addAccessors(env, accessors, binder){ 21 | binder = binder || prefixSlot; 22 | env.closure = env("({\n\t" + 23 | (accessors === true ? 24 | env.keys.map(binder).join(",\n\t") : 25 | accessors.replace(/([,\s]*)(\b\w+\b)/g, function(_, spaces, name){ 26 | return (spaces ? ",\n\t" : "") + binder(name); 27 | }) 28 | ) + 29 | "\n})"); 30 | } 31 | evalWithEnv.addAccessors = addAccessors; 32 | 33 | function inlineSlot(name){ 34 | return "get " + name + "(){ return " + name + 35 | "; }, set " + name + "(value){ return " + name + " = value; }"; 36 | } 37 | evalWithEnv.inlineSlot = inlineSlot; 38 | 39 | function functionSlot(name){ 40 | return name + ": function(value){ return arguments.length < 1 ? " + 41 | name + " : " + name + " = value; }"; 42 | } 43 | evalWithEnv.functionSlot = functionSlot; 44 | 45 | function doubleSlot(name){ 46 | return name + ": {get: function(){ return " + name + 47 | "; }, set: function(value){ return " + name + " = value; }}"; 48 | } 49 | evalWithEnv.doubleSlot = doubleSlot; 50 | 51 | function prefixSlot(name){ 52 | var capitalizedName = name.charAt(0).toUpperCase() + name.substring(1); 53 | return "get" + capitalizedName + ": function(){ return " + name + 54 | "; }, set" + capitalizedName + " : function(value){ return " + name + " = value; }"; 55 | } 56 | evalWithEnv.prefixSlot = prefixSlot; 57 | 58 | return evalWithEnv; 59 | }); 60 | -------------------------------------------------------------------------------- /algos/mergeArrays.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 | (["../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(__x, __y){", 7 | " #{extInit}", 8 | " var __r = new Array(__x.length + __y.length), __rp = 0,", 9 | " __xp = 0, __xn = __x.length, __yp = 0, __yn = __y.length,", 10 | " a = __x[0], b = __y[0];", 11 | " while(__xp < __xn && __yp < __yn){", 12 | " #{decision}", 13 | " }", 14 | " while(__xp < __xn) __r[__rp++] = __x[__xp++];", 15 | " while(__yp < __yn) __r[__rp++] = __y[__yp++];", 16 | " return __r;", 17 | "})", 18 | "//@ sourceURL=#{name}" 19 | ], 20 | dTmpl1 = "if(${lessCond}){", 21 | dTmpl2 = [ 22 | " __r[__rp++] = a;", 23 | " a = __x[++__xp];", 24 | "}else{", 25 | " __r[__rp++] = b;", 26 | " b = __y[++__yp];", 27 | "}" 28 | ]; 29 | 30 | var uniqNumber = 0; 31 | 32 | return function(less, name){ 33 | var ext, props, decision, last; 34 | switch(typeof less){ 35 | case "function": 36 | ext = "var __e = __self.__e;"; 37 | props = {__e: less}; 38 | decision = ctr(dTmpl1, {lessCond: "__e(a, b)"}).lines; 39 | break; 40 | case "string": 41 | decision = ctr(dTmpl1, {lessCond: less}).lines; 42 | break; 43 | default: // Array 44 | if(less instanceof Array){ 45 | last = less.length - 1; 46 | decision = less.slice(0, last).concat( 47 | ctr(dTmpl1, {lessCond: less[last]}).lines 48 | ); 49 | }else{ 50 | decision = ctr(dTmpl1, {lessCond: "a < b"}).lines; 51 | } 52 | break; 53 | } 54 | return ctr( 55 | fTmpl, 56 | { 57 | extInit: ext, 58 | decision: decision.concat(dTmpl2), 59 | name: name || ("/algos/mergeArrays/" + (uniqNumber++)) 60 | }, 61 | props 62 | ); 63 | }; 64 | 65 | /* the model function 66 | function mergeArrays(x, y, less){ 67 | var r = new Array(x.length + y.length), rp = 0, 68 | xp = 0, xn = x.length, yp = 0, yn = y.length; 69 | while(xp < xn && yp < yn){ 70 | r[rp++] = less(x[xp], y[yp]) ? x[xp++] : y[yp++]; 71 | } 72 | while(xp < xn) r[rp++] = x[xp++]; 73 | while(yp < yn) r[rp++] = y[yp++]; 74 | return r; 75 | } 76 | */ 77 | }); 78 | -------------------------------------------------------------------------------- /algos/heap/push.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 | (["../../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(#{arg}b){", 7 | " #{extInit}", 8 | " #{init}", 9 | " var __i = __a.length;", 10 | " __a.push(b);", 11 | " while(__i){", 12 | " var __p = (__i - 1) >> 1, a = __a[__p];", 13 | " #{predCond}", 14 | " if(#{lessCond}) break;", 15 | " __a[__i] = a;", 16 | " __a[__p] = b;", 17 | " __i = __p;", 18 | " }", 19 | " return #{ret};", 20 | "})", 21 | "//@ sourceURL=#{name}" 22 | ]; 23 | 24 | var uniqNumber = 0; 25 | 26 | return function(less, opt){ 27 | var ext, props, pred, cond, last; 28 | switch(typeof less){ 29 | case "function": 30 | ext = "var __e = __self.__e;"; 31 | props = {__e: less}; 32 | cond = "__e(a, b)"; 33 | break; 34 | case "string": 35 | cond = less; 36 | break; 37 | default: // Array 38 | if(less instanceof Array){ 39 | last = less.length - 1; 40 | pred = less.slice(0, last); 41 | cond = less[last]; 42 | }else{ 43 | cond = "a < b"; 44 | } 45 | break; 46 | } 47 | var arg = "__a, ", init = [], ret = "__a"; 48 | if(opt && opt.member){ 49 | arg = ""; 50 | init = "var __a = this." + opt.member + ";"; 51 | ret = "this"; 52 | } 53 | if(!opt || !opt.min){ 54 | cond = "!(" + cond + ")"; 55 | } 56 | return ctr( 57 | fTmpl, 58 | { 59 | arg: arg, 60 | init: init, 61 | ret: ret, 62 | extInit: ext, 63 | predCond: pred, 64 | lessCond: cond, 65 | name: (typeof opt == "string" && opt) || (opt && opt.name) || 66 | ("/algos/heap/push" + (uniqNumber++)) 67 | }, 68 | props 69 | ); 70 | }; 71 | 72 | /* 73 | // The model function: 74 | 75 | function push(__a, b, __less){ 76 | var __i = __a.length; 77 | __a.push(b); 78 | while(__i){ 79 | var __p = (__i - 1) >> 1, a = __a[__p]; 80 | if(!__less(a, b)){ 81 | break; 82 | } 83 | __a[__i] = a; 84 | __a[__p] = b; 85 | __i = __p; 86 | } 87 | } 88 | 89 | // useful index formulas: 90 | 91 | left = 2 * parent + 1 92 | right = 2 * parent + 2 93 | parent = Math.floor((child - 1) / 2) 94 | */ 95 | }); 96 | -------------------------------------------------------------------------------- /algos/binarySearch.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 | (["../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var aTmpl = [ 6 | "(function __self(__a, b, __l, ${right}){", 7 | " #{extInit}", 8 | " ${right} = Math.min(isNaN(${right}) ? __a.length : Math.max(0, ${right}), __a.length);", 9 | " __l = Math.min(isNaN(__l) ? 0 : Math.max(0, __l), ${right});", 10 | " #{downcast}", 11 | " while(__l < __r){", 12 | " var __m = ((__r - __l) >> 1) + __l,", 13 | " a = __a[__m];", 14 | " #{decision}", 15 | " }", 16 | " #{result}", 17 | "})", 18 | "//@ sourceURL=#{name}" 19 | ], 20 | dTmpl1 = "if(${lessCond}){", 21 | dTmpl2 = [ 22 | " __l = __m + 1;", 23 | "}else{", 24 | " __r = __m;", 25 | "}" 26 | ], 27 | fTmpl1 = [ 28 | "if(__l >= __R) return -(__l + 1);", 29 | "a = b, b = __a[__l];" 30 | ], 31 | fTmpl2 = [ 32 | " return -(__l + 1);", 33 | "}", 34 | "return __l;" 35 | ]; 36 | 37 | var uniqNumber = 0; 38 | 39 | return function(less, opt){ 40 | var ext, props = null, decision, last, result; 41 | switch(typeof less){ 42 | case "function": 43 | ext = "var __e = __self.__e;"; 44 | props = {__e: less}; 45 | decision = ctr(dTmpl1, {lessCond: "__e(a, b)"}).lines; 46 | break; 47 | case "string": 48 | decision = ctr(dTmpl1, {lessCond: less}).lines; 49 | break; 50 | default: // Array 51 | if(less instanceof Array){ 52 | last = less.length - 1; 53 | decision = less.slice(0, last).concat( 54 | ctr(dTmpl1, {lessCond: less[last]}).lines 55 | ); 56 | }else{ 57 | decision = ctr(dTmpl1, {lessCond: "a < b"}).lines; 58 | } 59 | break; 60 | } 61 | if(opt && opt.fail){ 62 | result = fTmpl1.concat(decision, fTmpl2); 63 | } 64 | return ctr( 65 | aTmpl, 66 | { 67 | extInit: ext, 68 | right: result ? "__R" : "__r", 69 | downcast: result ? "var __r = __R;" : undefined, 70 | decision: decision.concat(dTmpl2), 71 | result: result || "return __l;", 72 | name: (typeof opt == "string" && opt) || (opt && opt.name) || 73 | ("/algos/binarySearch/" + (uniqNumber++)) 74 | }, 75 | props 76 | ); 77 | }; 78 | 79 | /* 80 | // The model function: 81 | function bs(__a, b, __less){ 82 | var __l = 0, __r = __a.length; 83 | while(__l < __r){ 84 | var __m = ((__r - __l) >> 1) + __l, 85 | a = __a[__m]; 86 | if(__less(a, b)){ 87 | __l = __m + 1; 88 | }else{ 89 | __r = __m; 90 | } 91 | } 92 | return __l; 93 | } 94 | */ 95 | }); 96 | -------------------------------------------------------------------------------- /algos/heap/pop.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 | (["../../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(#{arg}){", 7 | " #{extInit}", 8 | " #{init}", 9 | " var __n = __a.length - 1;", 10 | " if(__n > 0){", 11 | " var a = __a[__n], b;", 12 | " __a[__n] = __a[0];", 13 | " __a[0] = a;", 14 | " for(var __i = 0, __c = 1; __c < __n; __i = __c, __c = (__i << 1) + 1){", 15 | " b = __a[__c];", 16 | " if(__c + 1 < __n){", 17 | " a = __a[__c + 1];", 18 | " #{predCond}", 19 | " if(#{lessCond}){", 20 | " ++__c;", 21 | " b = a;", 22 | " }", 23 | " }", 24 | " a = __a[__i];", 25 | " #{predCond}", 26 | " if(#{lessCond}) break;", 27 | " __a[__c] = a;", 28 | " __a[__i] = b;", 29 | " }", 30 | " }", 31 | " return __a.pop();", 32 | "})", 33 | "//@ sourceURL=#{name}" 34 | ]; 35 | 36 | var uniqNumber = 0; 37 | 38 | return function(less, opt){ 39 | var ext, props, pred, cond, last; 40 | switch(typeof less){ 41 | case "function": 42 | ext = "var __e = __self.__e;"; 43 | props = {__e: less}; 44 | cond = "__e(a, b)"; 45 | break; 46 | case "string": 47 | cond = less; 48 | break; 49 | default: // Array 50 | if(less instanceof Array){ 51 | last = less.length - 1; 52 | pred = less.slice(0, last); 53 | cond = less[last]; 54 | }else{ 55 | cond = "a < b"; 56 | } 57 | break; 58 | } 59 | var arg = "__a", init = []; 60 | if(opt && opt.member){ 61 | arg = ""; 62 | init = "var __a = this." + opt.member + ";"; 63 | } 64 | if(!opt || !opt.min){ 65 | cond = "!(" + cond + ")"; 66 | } 67 | return ctr( 68 | fTmpl, 69 | { 70 | arg: arg, 71 | init: init, 72 | extInit: ext, 73 | predCond: pred, 74 | lessCond: cond, 75 | name: (typeof opt == "string" && opt) || (opt && opt.name) || 76 | ("/algos/heap/pop" + (uniqNumber++)) 77 | }, 78 | props 79 | ); 80 | }; 81 | 82 | /* 83 | // The model function: 84 | 85 | function pop(__a, __less){ 86 | var __n = __a.length - 1; 87 | if(__n > 0){ 88 | var a = __a[__n], b; 89 | __a[__n] = __a[0]; 90 | __a[0] = a; 91 | for(var __i = 0, __c = 1; __c < __n; __i = __c, __c = 2 * __i + 1){ 92 | b = __a[__c]; 93 | if(__c + 1 < __n){ 94 | a = __a[__c + 1]; 95 | if(!__less(a, b)){ 96 | ++__c; 97 | b = a; 98 | } 99 | } 100 | a = __a[__i]; 101 | if(!__less(a, b)){ 102 | break; 103 | } 104 | __a[__c] = a; 105 | __a[__i] = b; 106 | } 107 | } 108 | return __a.pop(); 109 | } 110 | 111 | // useful index formulas: 112 | 113 | left = 2 * parent + 1 114 | right = 2 * parent + 2 115 | parent = Math.floor((child - 1) / 2) 116 | */ 117 | }); 118 | -------------------------------------------------------------------------------- /algos/heap/make.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 | (["../../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(#{arg}){", 7 | " #{extInit}", 8 | " #{init}", 9 | " if(__a.length > 1){", 10 | " for(var __n = __a.length, __j = (__n >> 1) - 1, a, b; __j >= 0; --__j){", 11 | " for(var __i = __j, __c = (__i << 1) + 1; __c < __n; __c = (__i << 1) + 1){", 12 | " b = __a[__c];", 13 | " if(__c + 1 < __n){", 14 | " a = __a[__c + 1];", 15 | " #{predCond}", 16 | " if(#{lessCond}){", 17 | " ++__c;", 18 | " b = a;", 19 | " }", 20 | " }", 21 | " a = __a[__i];", 22 | " #{predCond}", 23 | " if(#{lessCond}) break;", 24 | " __a[__c] = a;", 25 | " __a[__i] = b;", 26 | " __i = __c;", 27 | " }", 28 | " }", 29 | " }", 30 | " return #{ret};", 31 | "})", 32 | "//@ sourceURL=#{name}" 33 | ]; 34 | 35 | var uniqNumber = 0; 36 | 37 | return function(less, opt){ 38 | var ext, props, pred, cond, last; 39 | switch(typeof less){ 40 | case "function": 41 | ext = "var __e = __self.__e;"; 42 | props = {__e: less}; 43 | cond = "__e(a, b)"; 44 | break; 45 | case "string": 46 | cond = less; 47 | break; 48 | default: // Array 49 | if(less instanceof Array){ 50 | last = less.length - 1; 51 | pred = less.slice(0, last); 52 | cond = less[last]; 53 | }else{ 54 | cond = "a < b"; 55 | } 56 | break; 57 | } 58 | var arg = "__a", init = [], ret = arg; 59 | if(opt && opt.member){ 60 | arg = ""; 61 | init = "var __a = this." + opt.member + ";"; 62 | ret = "this"; 63 | } 64 | if(!opt || !opt.min){ 65 | cond = "!(" + cond + ")"; 66 | } 67 | return ctr( 68 | fTmpl, 69 | { 70 | arg: arg, 71 | init: init, 72 | ret: ret, 73 | extInit: ext, 74 | predCond: pred, 75 | lessCond: cond, 76 | name: (typeof opt == "string" && opt) || (opt && opt.name) || 77 | ("/algos/heap/make" + (uniqNumber++)) 78 | }, 79 | props 80 | ); 81 | }; 82 | 83 | /* 84 | // The model function: 85 | 86 | function make(__a, __less){ 87 | if(__a.length > 1){ 88 | for(var __n = __a.length, __j = __n >> 1 - 1, a, b; __j >= 0; --__j){ 89 | for(var __i = __j, __c = 2 * __i + 1; __c < __n; __i = __c, __c = 2 * __i + 1){ 90 | b = __a[__c]; 91 | if(__c + 1 < __n){ 92 | a = __a[__c + 1]; 93 | if(!__less(a, b)){ 94 | ++__c; 95 | b = a; 96 | } 97 | } 98 | a = __a[__i]; 99 | if(!__less(a, b)){ 100 | break; 101 | } 102 | __a[__c] = a; 103 | __a[__i] = b; 104 | } 105 | } 106 | } 107 | } 108 | 109 | // useful index formulas: 110 | 111 | left = 2 * parent + 1 112 | right = 2 * parent + 2 113 | parent = Math.floor((child - 1) / 2) 114 | */ 115 | }); 116 | -------------------------------------------------------------------------------- /algos/heap/sort.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 | (["../../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(#{arg}){", 7 | " #{extInit}", 8 | " #{init}", 9 | " if(__a.length > 1){", 10 | " for(var __n = __a.length - 1; __n; --__n){", 11 | " var a = __a[__n], b;", 12 | " __a[__n] = __a[0];", 13 | " __a[0] = a;", 14 | " for(var __i = 0, __c = 1; __c < __n; __i = __c, __c = (__i << 1) + 1){", 15 | " b = __a[__c];", 16 | " if(__c + 1 < __n){", 17 | " a = __a[__c + 1];", 18 | " #{predCond}", 19 | " if(#{lessCond}){", 20 | " ++__c;", 21 | " b = a;", 22 | " }", 23 | " }", 24 | " a = __a[__i];", 25 | " #{predCond}", 26 | " if(#{lessCond}) break;", 27 | " __a[__c] = a;", 28 | " __a[__i] = b;", 29 | " }", 30 | " }", 31 | " }", 32 | " return #{ret};", 33 | "})", 34 | "//@ sourceURL=#{name}" 35 | ]; 36 | 37 | var uniqNumber = 0; 38 | 39 | return function(less, opt){ 40 | var ext, props, pred, cond, last; 41 | switch(typeof less){ 42 | case "function": 43 | ext = "var __e = __self.__e;"; 44 | props = {__e: less}; 45 | cond = "__e(a, b)"; 46 | break; 47 | case "string": 48 | cond = less; 49 | break; 50 | default: // Array 51 | if(less instanceof Array){ 52 | last = less.length - 1; 53 | pred = less.slice(0, last); 54 | cond = less[last]; 55 | }else{ 56 | cond = "a < b"; 57 | } 58 | break; 59 | } 60 | var arg = "__a", init = [], ret = arg; 61 | if(opt && opt.member){ 62 | arg = ""; 63 | init = "var __a = this." + opt.member + ";"; 64 | ret = "this"; 65 | } 66 | if(!opt || !opt.min){ 67 | cond = "!(" + cond + ")"; 68 | } 69 | return ctr( 70 | fTmpl, 71 | { 72 | arg: arg, 73 | init: init, 74 | ret: ret, 75 | extInit: ext, 76 | predCond: pred, 77 | lessCond: cond, 78 | name: (typeof opt == "string" && opt) || (opt && opt.name) || 79 | ("/algos/heap/sort" + (uniqNumber++)) 80 | }, 81 | props 82 | ); 83 | }; 84 | 85 | /* 86 | // The model function: 87 | 88 | function sort(__a, __less){ 89 | if(__a.length > 1){ 90 | for(var __n = __a.length - 1; __n; --__n){ 91 | var a = __a[__n], b; 92 | __a[__n] = __a[0]; 93 | __a[0] = a; 94 | for(var __i = 0, __c = 1; __c < __n; __i = __c, __c = 2 * __i + 1){ 95 | b = __a[__c]; 96 | if(__c + 1 < __n){ 97 | a = __a[__c + 1]; 98 | if(!__less(a, b)){ 99 | ++__c; 100 | b = a; 101 | } 102 | } 103 | a = __a[__i]; 104 | if(!__less(a, b)){ 105 | break; 106 | } 107 | __a[__c] = a; 108 | __a[__i] = b; 109 | } 110 | } 111 | } 112 | } 113 | 114 | // useful index formulas: 115 | 116 | left = 2 * parent + 1 117 | right = 2 * parent + 2 118 | parent = Math.floor((child - 1) / 2) 119 | */ 120 | }); 121 | -------------------------------------------------------------------------------- /algos/quickSort.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 | (["../main"], function(ctr){ 3 | "use strict"; 4 | 5 | var fTmpl = [ 6 | "(function __self(__a, __L, __R){", 7 | " #{extInit}", 8 | " __R = Math.min(isNaN(__R) ? __a.length : Math.max(0, __R), __a.length);", 9 | " __L = Math.min(isNaN(__L) ? 0 : Math.max(0, __L), __R);", 10 | " --__R;", 11 | " var __backlog = [], __t, a, b;", 12 | " for(;;){", 13 | " var __l = __L, __r = __R, __pivot = __a[Math.floor(Math.random() * (__r - __l + 1)) + __l];", 14 | " while(__l <= __r){", 15 | " b = __pivot;", 16 | " for(;; ++__l){", 17 | " a = __a[__l];", 18 | " #{pred}", 19 | " }", 20 | " a = __pivot;", 21 | " for(;; --__r){", 22 | " b = __a[__r];", 23 | " #{pred}", 24 | " }", 25 | " if(__l <= __r){", 26 | " __t = __a[__l];", 27 | " __a[__l++] = __a[__r];", 28 | " __a[__r--] = __t;", 29 | " }", 30 | " }", 31 | " if(__L < __r){", 32 | " if(__l < __R){", 33 | " __backlog.push(__l, __R);", 34 | " }", 35 | " __R = __r;", 36 | " continue;", 37 | " }", 38 | " if(__l < __R){", 39 | " __L = __l;", 40 | " continue;", 41 | " }", 42 | " if(!__backlog.length){", 43 | " break;", 44 | " }", 45 | " __R = __backlog.pop();", 46 | " __L = __backlog.pop();", 47 | " }", 48 | " return __a;", 49 | "})", 50 | "//@ sourceURL=#{name}" 51 | ], 52 | dTmpl = "if(!(${lessCond})) break;"; 53 | 54 | var uniqNumber = 0; 55 | 56 | return function(less, name){ 57 | var ext, props, pred, last; 58 | switch(typeof less){ 59 | case "function": 60 | ext = "var __e = __self.__e;"; 61 | props = {__e: less}; 62 | pred = ctr(dTmpl, {lessCond: "__e(a, b)"}).lines; 63 | break; 64 | case "string": 65 | pred = ctr(dTmpl, {lessCond: less}).lines; 66 | break; 67 | default: // Array 68 | if(less instanceof Array){ 69 | last = less.length - 1; 70 | pred = less.slice(0, last).concat( 71 | ctr(dTmpl, {lessCond: less[last]}).lines 72 | ); 73 | }else{ 74 | pred = ctr(dTmpl, {lessCond: "a < b"}).lines; 75 | } 76 | break; 77 | } 78 | return ctr( 79 | fTmpl, 80 | { 81 | extInit: ext, 82 | pred: pred, 83 | name: name || ("/algos/quickSort/" + (uniqNumber++)) 84 | }, 85 | props 86 | ); 87 | }; 88 | 89 | /* 90 | // The model function: 91 | function qs(__a, __less){ 92 | var __L = 0, __R = __a.length - 1, __backlog = [], __t, a, b; 93 | for(;;){ 94 | var __l = __L, __r = __R, __pivot = __a[Math.floor(Math.random() * (__r - __l + 1)) + __l]; 95 | while(__l <= __r){ 96 | for(b = __pivot; a = __a[__l], __less(a, b); ++__l); 97 | for(a = __pivot; b = __a[__r], __less(a, b); --__r); 98 | if(__l <= __r){ 99 | // swap 100 | __t = __a[__l]; 101 | __a[__l++] = __a[__r]; 102 | __a[__r--] = __t; 103 | } 104 | } 105 | // next iteration 106 | if(__L < __r){ 107 | if(__l < __R){ 108 | __backlog.push(__l, __R); 109 | } 110 | __R = __r; 111 | continue; 112 | } 113 | if(__l < __R){ 114 | __L = __l; 115 | continue; 116 | } 117 | if(!__backlog.length){ 118 | break; 119 | } 120 | __R = __backlog.pop(); 121 | __L = __backlog.pop(); 122 | } 123 | return __a; 124 | } 125 | */ 126 | }); 127 | -------------------------------------------------------------------------------- /lambda.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 | (["./Target"], function(Target){ 3 | 4 | // This module adds high-level functions and related constructs: 5 | // - anonymous functions built from the string 6 | 7 | // Acknowledgements: 8 | // - lambda() is based on work by Oliver Steele 9 | // (http://osteele.com/sources/javascript/functional/functional.js) 10 | // which was published under MIT License 11 | 12 | // Notes: 13 | // - lambda() produces functions, which after the compilation step are 14 | // as fast as regular JS functions (at least theoretically). 15 | 16 | // Lambda input values: 17 | // - returns functions unchanged 18 | // - converts strings to functions 19 | // - converts arrays to a functional composition 20 | 21 | var lcache = {}; 22 | 23 | function identity(x){ return x; } 24 | 25 | function crackLambda(/*String*/ s){ 26 | // summary: 27 | // builds a function from a snippet, or array (composing), 28 | // returns an object describing the function; functions are 29 | // passed through unmodified. 30 | // description: 31 | // This method is to normalize a functional representation (a 32 | // text snippet) to an object that contains an array of 33 | // arguments, and a body , which is used to calculate the 34 | // returning value. 35 | var args = [], sects = s.split(/\s*->\s*/m); 36 | if(sects.length > 1){ 37 | while(sects.length){ 38 | s = sects.pop(); 39 | args = sects.pop().split(/\s*,\s*|\s+/m); 40 | if(sects.length){ 41 | sects.push("(function(" + args.join(", ") + "){ return (" + s + "); })"); 42 | } 43 | } 44 | }else if(s.match(/\b_\b/)){ 45 | args = ["_"]; 46 | }else{ 47 | var l = s.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), 48 | r = s.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); 49 | if(l || r){ 50 | if(l){ 51 | args.push("__$1"); 52 | s = "__$1" + s; 53 | } 54 | if(r){ 55 | args.push("__$2"); 56 | s = s + "__$2"; 57 | } 58 | }else{ 59 | // the point of the long regex below is to exclude all well-known 60 | // lower-case words from the list of potential arguments 61 | var vars = s. 62 | replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|true|false|null|undefined|typeof|instanceof|in|delete|new|void|arguments|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|escape|eval|isFinite|isNaN|parseFloat|parseInt|unescape|window|document|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, ""). 63 | match(/([a-z_$][a-z_$\d]*)/gi) || [], t = {}, i = 0, v; 64 | for(; i < vars.length; ++i){ 65 | v = vars[i]; 66 | if(!t.hasOwnProperty(v)){ 67 | args.push(v); 68 | t[v] = 1; 69 | } 70 | } 71 | } 72 | } 73 | return {args: args, body: s}; // Object 74 | }; 75 | 76 | function compose(/*Array*/ a){ 77 | return a.length ? 78 | function(){ 79 | var i = a.length - 1, x = lambda(a[i]).apply(this, arguments); 80 | for(--i; i >= 0; --i){ x = lambda(a[i]).call(this, x); } 81 | return x; 82 | } : identity; 83 | } 84 | 85 | function sourceLambda(/*String*/ s){ 86 | // summary: 87 | // builds a function from a snippet, returns a string, which 88 | // represents the function. 89 | // description: 90 | // This method returns a textual representation of a function 91 | // built from the snippet. It is meant to be evaled in the 92 | // proper context, so local variables can be pulled from the 93 | // environment. 94 | var l = crackLambda(s); 95 | return "(function(" + l.args.join(", ") + "){ return (" + l.body + "); })"; // String 96 | } 97 | 98 | function buildLambda(s, props){ 99 | return new Target([sourceLambda(s)], props); 100 | } 101 | 102 | function lambda(/*Function|String|Array*/ s){ 103 | // summary: 104 | // builds a function from a snippet, or array (composing), 105 | // returns a function object; functions are passed through 106 | // unmodified. 107 | // description: 108 | // This method is used to normalize a functional 109 | // representation (a text snippet, an array, or a function) to 110 | // a function object. 111 | if(s instanceof Array){ return compose(s); } 112 | if(typeof s == "string"){ 113 | if(lcache.hasOwnProperty(s)){ return lcache[s]; } 114 | var l = crackLambda(s); 115 | // the next assignment is intentional 116 | return lcache[s] = new Function(l.args, "return (" + l.body + ");"); // Function 117 | } 118 | return s; 119 | } 120 | 121 | lambda.crack = crackLambda; 122 | lambda.build = buildLambda; 123 | lambda.source = sourceLambda; 124 | lambda.clearCache = function(){ lcache = {}; }; 125 | 126 | return lambda; 127 | }); 128 | -------------------------------------------------------------------------------- /tests/test_algos_binarySearch.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", "../algos/binarySearch"], 3 | function(module, unit, bsearch){ 4 | "use strict"; 5 | 6 | function cmpNum(a, b){ return a - b; } 7 | 8 | unit.add(module, [ 9 | function test_simple(t){ 10 | var bs = bsearch().compile(); 11 | 12 | eval(t.TEST("bs([], 1) === 0")); 13 | eval(t.TEST("bs([], 2) === 0")); 14 | eval(t.TEST("bs([], 3) === 0")); 15 | 16 | eval(t.TEST("bs([2], 1) === 0")); 17 | eval(t.TEST("bs([2], 2) === 0")); 18 | eval(t.TEST("bs([2], 3) === 1")); 19 | 20 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 0) === 0")); 21 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 1) === 0")); 22 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 2) === 0")); 23 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 3) === 2")); 24 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 4) === 4")); 25 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 5) === 6")); 26 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 6) === 7")); 27 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 7) === 8")); 28 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 8) === 8")); 29 | eval(t.TEST("bs([2, 2, 3, 3, 4, 4, 5, 6, 8], 9) === 9")); 30 | 31 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 32 | "'seven', 'six', 'three', 'two', 'zero' ], 'lorem') === 3")); 33 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 34 | "'seven', 'six', 'three', 'two', 'zero' ], 'ipsum') === 3")); 35 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 36 | "'seven', 'six', 'three', 'two', 'zero' ], 'dolor') === 0")); 37 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 38 | "'seven', 'six', 'three', 'two', 'zero' ], 'sit') === 6")); 39 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 40 | "'seven', 'six', 'three', 'two', 'zero' ], 'amet') === 0")); 41 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 42 | "'seven', 'six', 'three', 'two', 'zero' ], 'consectetur') === 0")); 43 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 44 | "'seven', 'six', 'three', 'two', 'zero' ], 'adipisicing') === 0")); 45 | eval(t.TEST("bs(['eight', 'five', 'four', 'nine', 'one', " + 46 | "'seven', 'six', 'three', 'two', 'zero' ], 'elit') === 1")); 47 | }, 48 | function test_random(t){ 49 | var bs = bsearch("a < b").compile(); 50 | 51 | var arrays = 10, size = 100, tests = 10; 52 | for(var i = 0; i < arrays; ++i){ 53 | var a = new Array(size); 54 | for(var j = 0; j < size; ++j){ 55 | a[j] = Math.random(); 56 | } 57 | a.sort(cmpNum); 58 | for(j = 0; j < tests; ++j){ 59 | var value = Math.random(), 60 | index = bs(a, value); 61 | eval(t.TEST("index >= 0 && index <= a.length")); 62 | eval(t.TEST("(index === a.length || value <= a[index]) && (index === 0 || a[index - 1] < value)")); 63 | } 64 | } 65 | }, 66 | function test_external(t){ 67 | var bs = bsearch(function(a, b){ return a < b; }).compile(); 68 | 69 | var arrays = 10, size = 100, tests = 10; 70 | for(var i = 0; i < arrays; ++i){ 71 | var a = new Array(size); 72 | for(var j = 0; j < size; ++j){ 73 | a[j] = Math.random(); 74 | } 75 | a.sort(cmpNum); 76 | for(j = 0; j < tests; ++j){ 77 | var value = Math.random(), 78 | index = bs(a, value); 79 | eval(t.TEST("index >= 0 && index <= a.length")); 80 | eval(t.TEST("(index === a.length || value <= a[index]) && (index === 0 || a[index - 1] < value)")); 81 | } 82 | } 83 | }, 84 | function test_fail_random(t){ 85 | var bs = bsearch("a < b", {fail: true}).compile(); 86 | 87 | var arrays = 10, size = 100, tests = 10; 88 | for(var i = 0; i < arrays; ++i){ 89 | var a = new Array(size); 90 | for(var j = 0; j < size; ++j){ 91 | a[j] = Math.random(); 92 | } 93 | a.sort(cmpNum); 94 | for(j = 0; j < tests; ++j){ 95 | var value = Math.random(), 96 | index = bs(a, value); 97 | eval(t.TEST("index < a.length")); 98 | if(index < 0){ 99 | index = -index - 1; 100 | eval(t.TEST("(index === a.length || value < a[index]) && (index === 0 || a[index - 1] < value)")); 101 | }else{ 102 | eval(t.TEST("a[index] === value")); 103 | } 104 | } 105 | } 106 | }, 107 | function test_fail_external(t){ 108 | var bs = bsearch(function(a, b){ return a < b; }, {fail: true}).compile(); 109 | 110 | var arrays = 10, size = 100, tests = 10; 111 | for(var i = 0; i < arrays; ++i){ 112 | var a = new Array(size); 113 | for(var j = 0; j < size; ++j){ 114 | a[j] = Math.random(); 115 | } 116 | a.sort(cmpNum); 117 | for(j = 0; j < tests; ++j){ 118 | var value = Math.random(), 119 | index = bs(a, value); 120 | eval(t.TEST("index < a.length")); 121 | if(index < 0){ 122 | index = -index - 1; 123 | eval(t.TEST("(index === a.length || value < a[index]) && (index === 0 || a[index - 1] < value)")); 124 | }else{ 125 | eval(t.TEST("a[index] === value")); 126 | } 127 | } 128 | } 129 | } 130 | ]); 131 | 132 | return {}; 133 | }); 134 | -------------------------------------------------------------------------------- /tests/test_algos_heap.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", "../algos/heap/make", "../algos/heap/pop", 3 | "../algos/heap/push", "../algos/heap/sort"], 4 | function(module, unit, makeHeap, popHeap, pushHeap, sortHeap){ 5 | "use strict"; 6 | 7 | function cmpNum(a, b){ return a - b; } 8 | function identity(x) { return x; } 9 | function less(a, b) { return a < b; } 10 | 11 | var sample = [42, 55, 73, 21, 83, 90, 79, 83, 81, 93, 97, 84]; 12 | 13 | function walk(heap, fn, index){ 14 | index = index || 0; 15 | if(index < heap.length){ 16 | fn(heap, index); 17 | walk(heap, fn, 2 * index + 1); 18 | walk(heap, fn, 2 * index + 2); 19 | } 20 | } 21 | 22 | unit.add(module, [ 23 | function test_maxHeap_make(t){ 24 | var make = makeHeap().compile(); 25 | var heap = make(sample.map(identity)); 26 | walk(heap, function(heap, index){ 27 | var l = 2 * index + 1, r = l + 1; 28 | t.assert(l >= heap.length || heap[index] >= heap[l], "left child is larger than its parent"); 29 | t.assert(r >= heap.length || heap[index] >= heap[r], "right child is larger than its parent"); 30 | }); 31 | }, 32 | function test_maxHeap_make_external(t){ 33 | var make = makeHeap(less).compile(); 34 | var heap = make(sample.map(identity)); 35 | walk(heap, function(heap, index){ 36 | var l = 2 * index + 1, r = l + 1; 37 | t.assert(l >= heap.length || heap[index] >= heap[l], "left child is larger than its parent"); 38 | t.assert(r >= heap.length || heap[index] >= heap[r], "right child is larger than its parent"); 39 | }); 40 | }, 41 | function test_maxHeap_pop(t){ 42 | var make = makeHeap().compile(); 43 | var pop = popHeap().compile(); 44 | var heap = make(sample.map(identity)); 45 | 46 | var a = sample.map(identity).sort(cmpNum).reverse(); 47 | 48 | var b = []; 49 | while(heap.length){ 50 | b.push(pop(heap)); 51 | } 52 | 53 | eval(t.ASSERT("t.unify(a, b)")); 54 | }, 55 | function test_maxHeap_pop_external(t){ 56 | var make = makeHeap(less).compile(); 57 | var pop = popHeap(less).compile(); 58 | var heap = make(sample.map(identity)); 59 | 60 | var a = sample.map(identity).sort(cmpNum).reverse(); 61 | 62 | var b = []; 63 | while(heap.length){ 64 | b.push(pop(heap)); 65 | } 66 | 67 | eval(t.ASSERT("t.unify(a, b)")); 68 | }, 69 | function test_maxHeap_push(t){ 70 | var push = pushHeap().compile(); 71 | var pop = popHeap().compile(); 72 | 73 | var heap = []; 74 | sample.forEach(function(value){ 75 | push(heap, value); 76 | }); 77 | 78 | var a = sample.map(identity).sort(cmpNum).reverse(); 79 | 80 | var b = []; 81 | while(heap.length){ 82 | b.push(pop(heap)); 83 | } 84 | 85 | eval(t.ASSERT("t.unify(a, b)")); 86 | }, 87 | function test_maxHeap_push_external(t){ 88 | var push = pushHeap(less).compile(); 89 | var pop = popHeap(less).compile(); 90 | 91 | var heap = []; 92 | sample.forEach(function(value){ 93 | push(heap, value); 94 | }); 95 | 96 | var a = sample.map(identity).sort(cmpNum).reverse(); 97 | 98 | var b = []; 99 | while(heap.length){ 100 | b.push(pop(heap)); 101 | } 102 | 103 | eval(t.ASSERT("t.unify(a, b)")); 104 | }, 105 | function test_maxHeap_sort(t){ 106 | var make = makeHeap().compile(); 107 | var sort = sortHeap().compile(); 108 | 109 | var heap = make(sample.map(identity)); 110 | sort(heap); 111 | 112 | var a = sample.map(identity).sort(cmpNum); 113 | 114 | eval(t.ASSERT("t.unify(a, heap)")); 115 | }, 116 | function test_maxHeap_sort_external(t){ 117 | var make = makeHeap(less).compile(); 118 | var sort = sortHeap(less).compile(); 119 | 120 | var heap = make(sample.map(identity)); 121 | sort(heap); 122 | 123 | var a = sample.map(identity).sort(cmpNum); 124 | 125 | eval(t.ASSERT("t.unify(a, heap)")); 126 | }, 127 | function test_maxHeap_object(t){ 128 | function MaxHeap(a){ 129 | if(a){ 130 | this.init(a); 131 | }else{ 132 | this.array = []; 133 | } 134 | } 135 | 136 | var make = makeHeap(null, {member: "array"}).compile(); 137 | var push = pushHeap(null, {member: "array"}).compile(); 138 | var pop = popHeap (null, {member: "array"}).compile(); 139 | var sort = sortHeap(null, {member: "array"}).compile(); 140 | 141 | MaxHeap.prototype = { 142 | init: function(a){ 143 | this.array = a.map(identity); 144 | return this._make(); 145 | }, 146 | empty: function(){ return !this.array.length; }, 147 | push: push, 148 | pop: pop, 149 | sort: sort, 150 | _make: make 151 | }; 152 | 153 | var sorted = sample.map(identity).sort(cmpNum); 154 | 155 | var heap = new MaxHeap(sample); 156 | 157 | var a = []; 158 | while(!heap.empty()){ 159 | a.push(heap.pop()); 160 | } 161 | a.reverse(); 162 | eval(t.TEST("t.unify(sorted, a)")); 163 | 164 | sample.forEach(function(value){ 165 | heap.push(value); 166 | }); 167 | heap.sort(); 168 | eval(t.TEST("t.unify(sorted, heap.array)")); 169 | }, 170 | function test_minHeap_make(t){ 171 | var make = makeHeap(null, {min: true}).compile(); 172 | var heap = make(sample.map(identity)); 173 | walk(heap, function(heap, index){ 174 | var l = 2 * index + 1, r = l + 1; 175 | t.assert(l >= heap.length || heap[index] <= heap[l], "left child is smaller than its parent"); 176 | t.assert(r >= heap.length || heap[index] <= heap[r], "right child is smaller than its parent"); 177 | }); 178 | }, 179 | function test_minHeap_make_external(t){ 180 | var make = makeHeap(less, {min: true}).compile(); 181 | var heap = make(sample.map(identity)); 182 | walk(heap, function(heap, index){ 183 | var l = 2 * index + 1, r = l + 1; 184 | t.assert(l >= heap.length || heap[index] <= heap[l], "left child is smaller than its parent"); 185 | t.assert(r >= heap.length || heap[index] <= heap[r], "right child is smaller than its parent"); 186 | }); 187 | }, 188 | function test_minHeap_pop(t){ 189 | var make = makeHeap(null, {min: true}).compile(); 190 | var pop = popHeap (null, {min: true}).compile(); 191 | var heap = make(sample.map(identity)); 192 | 193 | var a = sample.map(identity).sort(cmpNum); 194 | 195 | var b = []; 196 | while(heap.length){ 197 | b.push(pop(heap)); 198 | } 199 | 200 | eval(t.ASSERT("t.unify(a, b)")); 201 | }, 202 | function test_minHeap_pop_external(t){ 203 | var make = makeHeap(less, {min: true}).compile(); 204 | var pop = popHeap (less, {min: true}).compile(); 205 | var heap = make(sample.map(identity)); 206 | 207 | var a = sample.map(identity).sort(cmpNum); 208 | 209 | var b = []; 210 | while(heap.length){ 211 | b.push(pop(heap)); 212 | } 213 | 214 | eval(t.ASSERT("t.unify(a, b)")); 215 | }, 216 | function test_minHeap_push(t){ 217 | var push = pushHeap(null, {min: true}).compile(); 218 | var pop = popHeap (null, {min: true}).compile(); 219 | 220 | var heap = []; 221 | sample.forEach(function(value){ 222 | push(heap, value); 223 | }); 224 | 225 | var a = sample.map(identity).sort(cmpNum); 226 | 227 | var b = []; 228 | while(heap.length){ 229 | b.push(pop(heap)); 230 | } 231 | 232 | eval(t.ASSERT("t.unify(a, b)")); 233 | }, 234 | function test_minHeap_push_external(t){ 235 | var push = pushHeap(less, {min: true}).compile(); 236 | var pop = popHeap (less, {min: true}).compile(); 237 | 238 | var heap = []; 239 | sample.forEach(function(value){ 240 | push(heap, value); 241 | }); 242 | 243 | var a = sample.map(identity).sort(cmpNum); 244 | 245 | var b = []; 246 | while(heap.length){ 247 | b.push(pop(heap)); 248 | } 249 | 250 | eval(t.ASSERT("t.unify(a, b)")); 251 | }, 252 | function test_minHeap_sort(t){ 253 | var make = makeHeap(null, {min: true}).compile(); 254 | var sort = sortHeap(null, {min: true}).compile(); 255 | 256 | var heap = make(sample.map(identity)); 257 | sort(heap); 258 | 259 | var a = sample.map(identity).sort(cmpNum).reverse(); 260 | 261 | eval(t.ASSERT("t.unify(a, heap)")); 262 | }, 263 | function test_minHeap_sort_external(t){ 264 | var make = makeHeap(less, {min: true}).compile(); 265 | var sort = sortHeap(less, {min: true}).compile(); 266 | 267 | var heap = make(sample.map(identity)); 268 | sort(heap); 269 | 270 | var a = sample.map(identity).sort(cmpNum).reverse(); 271 | 272 | eval(t.ASSERT("t.unify(a, heap)")); 273 | }, 274 | function test_minHeap_object(t){ 275 | function MinHeap(a){ 276 | if(a){ 277 | this.init(a); 278 | }else{ 279 | this.array = []; 280 | } 281 | } 282 | 283 | var make = makeHeap(null, {member: "array", min: true}).compile(); 284 | var push = pushHeap(null, {member: "array", min: true}).compile(); 285 | var pop = popHeap (null, {member: "array", min: true}).compile(); 286 | var sort = sortHeap(null, {member: "array", min: true}).compile(); 287 | 288 | MinHeap.prototype = { 289 | init: function(a){ 290 | this.array = a.map(identity); 291 | return this._make(); 292 | }, 293 | empty: function(){ return !this.array.length; }, 294 | push: push, 295 | pop: pop, 296 | sort: sort, 297 | _make: make 298 | }; 299 | 300 | var sorted = sample.map(identity).sort(cmpNum); 301 | 302 | var heap = new MinHeap(sample); 303 | 304 | var a = []; 305 | while(!heap.empty()){ 306 | a.push(heap.pop()); 307 | } 308 | eval(t.TEST("t.unify(sorted, a)")); 309 | 310 | sample.forEach(function(value){ 311 | heap.push(value); 312 | }); 313 | heap.sort(); 314 | sorted.reverse(); 315 | eval(t.TEST("t.unify(sorted, heap.array)")); 316 | } 317 | ]); 318 | 319 | return {}; 320 | }); 321 | -------------------------------------------------------------------------------- /tests/test_main.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", "../count", "../replace", "../main", 3 | "../jst", "../Pool", "../evalWithEnv", "../lambda"], 4 | function(module, unit, count, replace, ctr, jst, Pool, evalWithEnv, lambda){ 5 | "use strict"; 6 | 7 | var countOwnProperties; 8 | if(Object.keys){ 9 | countOwnProperties = function(object){ 10 | return Object.keys(object).length; 11 | }; 12 | }else{ 13 | countOwnProperties = function(object){ 14 | var count = 0; 15 | for(var name in object){ 16 | if(object.hasOwnProperty(name)){ 17 | ++count; 18 | } 19 | } 20 | return count; 21 | }; 22 | } 23 | 24 | var sorryTmpl1 = [ 25 | "I am<% if(count > 0){", 26 | " while(count--){", 27 | " if(count){", 28 | " %> very<%", 29 | " }", 30 | " }", 31 | " }else{", 32 | " %> not<%", 33 | " }", 34 | " %> sorry." 35 | ].join("\n"); 36 | 37 | var sorryTmpl2 = [ 38 | "I am<% if(count > 0){", 39 | " while(count--){", 40 | " if(count){", 41 | " print(\" very\");", 42 | " }", 43 | " }", 44 | " }else{", 45 | " print(\" not\");", 46 | " }", 47 | " %> sorry." 48 | ].join("\n"); 49 | 50 | // tests 51 | 52 | unit.add(module, [ 53 | // evalWithEnv() tests 54 | function test_evalWithEnv_eval(t){ 55 | var x = 42; 56 | eval(t.TEST('evalWithEnv({a: 1, b: 2})("a + b") === 3')); 57 | eval(t.TEST('evalWithEnv({a: 1, b: 2})("typeof a + typeof x") === "numberundefined"')); 58 | eval(t.TEST('evalWithEnv({a: 1, b: 2})("typeof b + typeof y") === "numberundefined"')); 59 | }, 60 | function test_evalWithEnv_defaultAccessors(t){ 61 | var f = evalWithEnv({a: 1, b: 2}, "a b"), 62 | g = f("(function(c){ return a + b + c; })"); 63 | eval(t.TEST('g(3) === 6')); 64 | eval(t.TEST('f.closure.getA() === 1')); 65 | eval(t.TEST('f.closure.getB() === 2')); 66 | eval(t.TEST('f.closure.setA(4) === 4')); 67 | eval(t.TEST('g(3) === 9')); 68 | eval(t.TEST('f.closure.setB(5) === 5')); 69 | eval(t.TEST('g(3) === 12')); 70 | eval(t.TEST('f.closure.getA() === 4')); 71 | eval(t.TEST('f.closure.getB() === 5')); 72 | }, 73 | function test_evalWithEnv_prefixAccessors(t){ 74 | var f = evalWithEnv({a: 1, b: 2}, "a b", evalWithEnv.prefixSlot), 75 | g = f("(function(c){ return a + b + c; })"); 76 | eval(t.TEST('g(3) === 6')); 77 | eval(t.TEST('f.closure.getA() === 1')); 78 | eval(t.TEST('f.closure.getB() === 2')); 79 | eval(t.TEST('f.closure.setA(4) === 4')); 80 | eval(t.TEST('g(3) === 9')); 81 | eval(t.TEST('f.closure.setB(5) === 5')); 82 | eval(t.TEST('g(3) === 12')); 83 | eval(t.TEST('f.closure.getA() === 4')); 84 | eval(t.TEST('f.closure.getB() === 5')); 85 | }, 86 | function test_evalWithEnv_inlineAccessors(t){ 87 | var f = evalWithEnv({a: 1, b: 2}, "a b", evalWithEnv.inlineSlot), 88 | g = f("(function(c){ return a + b + c; })"); 89 | eval(t.TEST('g(3) === 6')); 90 | eval(t.TEST('f.closure.a === 1')); 91 | eval(t.TEST('f.closure.b === 2')); 92 | eval(t.TEST('(f.closure.a = 4) === 4')); 93 | eval(t.TEST('g(3) === 9')); 94 | eval(t.TEST('(f.closure.b = 5) === 5')); 95 | eval(t.TEST('g(3) === 12')); 96 | eval(t.TEST('f.closure.a === 4')); 97 | eval(t.TEST('f.closure.b === 5')); 98 | }, 99 | function test_evalWithEnv_doubleAccessors(t){ 100 | var f = evalWithEnv({a: 1, b: 2}, "a b", evalWithEnv.doubleSlot), 101 | g = f("(function(c){ return a + b + c; })"); 102 | eval(t.TEST('g(3) === 6')); 103 | eval(t.TEST('f.closure.a.get() === 1')); 104 | eval(t.TEST('f.closure.b.get() === 2')); 105 | eval(t.TEST('f.closure.a.set(4) === 4')); 106 | eval(t.TEST('g(3) === 9')); 107 | eval(t.TEST('f.closure.b.set(5) === 5')); 108 | eval(t.TEST('g(3) === 12')); 109 | eval(t.TEST('f.closure.a.get() === 4')); 110 | eval(t.TEST('f.closure.b.get() === 5')); 111 | }, 112 | function test_evalWithEnv_functionAccessors(t){ 113 | var f = evalWithEnv({a: 1, b: 2}, "a b", evalWithEnv.functionSlot), 114 | g = f("(function(c){ return a + b + c; })"); 115 | eval(t.TEST('g(3) === 6')); 116 | eval(t.TEST('f.closure.a() === 1')); 117 | eval(t.TEST('f.closure.b() === 2')); 118 | eval(t.TEST('f.closure.a(4) === 4')); 119 | eval(t.TEST('g(3) === 9')); 120 | eval(t.TEST('f.closure.b(5) === 5')); 121 | eval(t.TEST('g(3) === 12')); 122 | eval(t.TEST('f.closure.a() === 4')); 123 | eval(t.TEST('f.closure.b() === 5')); 124 | }, 125 | function test_evalWithEnv_defaultFullAccessors(t){ 126 | var f = evalWithEnv({a: 1, b: 2}, true), 127 | g = f("(function(c){ return a + b + c; })"); 128 | eval(t.TEST('g(3) === 6')); 129 | eval(t.TEST('f.closure.getA() === 1')); 130 | eval(t.TEST('f.closure.getB() === 2')); 131 | eval(t.TEST('f.closure.setA(4) === 4')); 132 | eval(t.TEST('g(3) === 9')); 133 | eval(t.TEST('f.closure.setB(5) === 5')); 134 | eval(t.TEST('g(3) === 12')); 135 | eval(t.TEST('f.closure.getA() === 4')); 136 | eval(t.TEST('f.closure.getB() === 5')); 137 | }, 138 | function test_evalWithEnv_defaultCommaAccessors(t){ 139 | var f = evalWithEnv({a: 1, b: 2}, "a, b"), 140 | g = f("(function(c){ return a + b + c; })"); 141 | eval(t.TEST('g(3) === 6')); 142 | eval(t.TEST('f.closure.getA() === 1')); 143 | eval(t.TEST('f.closure.getB() === 2')); 144 | eval(t.TEST('f.closure.setA(4) === 4')); 145 | eval(t.TEST('g(3) === 9')); 146 | eval(t.TEST('f.closure.setB(5) === 5')); 147 | eval(t.TEST('g(3) === 12')); 148 | eval(t.TEST('f.closure.getA() === 4')); 149 | eval(t.TEST('f.closure.getB() === 5')); 150 | }, 151 | // Pool tests 152 | function test_pool(t){ 153 | var pool = new Pool; 154 | eval(t.TEST('!pool.getTop()')); 155 | var env = pool.newEnv(); 156 | eval(t.TEST('countOwnProperties(env) == 0')); 157 | env.a = 42; 158 | pool.commit(env); 159 | env = pool.getTop(); 160 | eval(t.TEST('countOwnProperties(env) == 1')); 161 | eval(t.TEST('env.a === 42')); 162 | env = pool.newEnv(); 163 | eval(t.TEST('countOwnProperties(env) == 0')); 164 | eval(t.TEST('env.a === 42')); 165 | env.b = 13; 166 | eval(t.TEST('countOwnProperties(env) == 1')); 167 | eval(t.TEST('env.b === 13')); 168 | pool.merge(env); 169 | env = pool.getTop(); 170 | eval(t.TEST('countOwnProperties(env) == 2')); 171 | eval(t.TEST('env.a === 42')); 172 | eval(t.TEST('env.b === 13')); 173 | }, 174 | // count() tests 175 | function test_simple_counts(t){ 176 | "use strict"; 177 | var dict = count("$${a} ${a} ${b} ${a}"); 178 | eval(t.TEST('dict.a === 2')); 179 | eval(t.TEST(' dict.b === 1')); 180 | if(Object.keys){ 181 | eval(t.TEST('Object.keys(dict).length == 2')); 182 | } 183 | }, 184 | function test_complex_counts(t){ 185 | "use strict"; 186 | var dict = count("$${a}x${a}-${b}.$$${b}/${a}${a }", {b: 1, c: 2}); 187 | eval(t.TEST('dict.a === 2')); 188 | eval(t.TEST('dict.b === 2')); 189 | eval(t.TEST('dict.c === 2')); 190 | if(Object.keys){ 191 | eval(t.TEST('Object.keys(dict).length == 3')); 192 | } 193 | }, 194 | // replace() tests 195 | function test_simple_replace(t){ 196 | "use strict"; 197 | var text = replace("$${a} ${a} ${b} ${a}", {a: "xxx", b: 777}); 198 | eval(t.TEST('text === "${a} xxx 777 xxx"')); 199 | }, 200 | function test_complex_replace(t){ 201 | "use strict"; 202 | var text = replace("$${a}x${a}-${b}\n.$$${b}/${a}${a }", {a: "yyy", b: 42, c: null}); 203 | eval(t.TEST('text === "${a}xyyy-42\\n.$${b}/yyy${a }"')); 204 | }, 205 | // ctr() tests 206 | function test_simple_ctr(t){ 207 | "use strict"; 208 | var text = ctr( 209 | "(function(${args}){\n" + 210 | " #{body}\n" + 211 | "})", 212 | { 213 | args: "", 214 | body: "return 'Hello, world!';" 215 | } 216 | ).getCode(); 217 | eval(t.TEST('text ===' + 218 | '"(function(){\\n" +' + 219 | '" return \'Hello, world!\';\\n" +' + 220 | '"})"')); 221 | }, 222 | function test_complex_ctr(t){ 223 | "use strict"; 224 | var text = ctr( 225 | [ 226 | "(function(${args}){", 227 | " #{body}", 228 | "})" 229 | ], 230 | { 231 | args: "a, b", 232 | body: [ 233 | "var c = a + b;", 234 | "return c;" 235 | ] 236 | } 237 | ).getCode(); 238 | eval(t.TEST('text ===' + 239 | '"(function(a, b){\\n" +' + 240 | '" var c = a + b;\\n" +' + 241 | '" return c;\\n" +' + 242 | '"})"')); 243 | }, 244 | // JST tests 245 | function test_jst_simple1(t){ 246 | var text = jst([ 247 | "Hello, <%= name %>!" 248 | ]).compile({ 249 | name: "world" 250 | })(); 251 | eval(t.TEST('text === "Hello, world!"')); 252 | }, 253 | function test_jst_simple2(t){ 254 | var text = jst("Hello, Bob's <%= name %>!").compile({ 255 | name: "world" 256 | })(); 257 | eval(t.TEST('text === "Hello, Bob\'s world!"')); 258 | }, 259 | function test_jst_simple3(t){ 260 | var text = jst("Hello, <%= name %>!").compile({ 261 | name: "Bob's world" 262 | })(); 263 | eval(t.TEST('text === "Hello, Bob\'s world!"')); 264 | }, 265 | function test_jst_sorry0(t){ 266 | var text = jst(sorryTmpl1).compile({count: 0})(); 267 | eval(t.TEST('text === "I am not sorry."')); 268 | }, 269 | function test_jst_sorry1(t){ 270 | var text = jst(sorryTmpl1).compile({count: 1})(); 271 | eval(t.TEST('text === "I am sorry."')); 272 | }, 273 | function test_jst_sorry2(t){ 274 | var text = jst(sorryTmpl1).compile({count: 2})(); 275 | eval(t.TEST('text === "I am very sorry."')); 276 | }, 277 | function test_jst_sorry3(t){ 278 | var text = jst(sorryTmpl1).compile({count: 3})(); 279 | eval(t.TEST('text === "I am very very sorry."')); 280 | }, 281 | function test_jst_sorry3_inline(t){ 282 | var text = jst(sorryTmpl2).compile({count: 3})(); 283 | eval(t.TEST('text === "I am very very sorry."')); 284 | }, 285 | // lambda tests 286 | function test_lambda(t){ 287 | eval(t.TEST("lambda('1 + _ + 2')(3) === 6")); 288 | eval(t.TEST("lambda('+1')(3) === 4")); 289 | eval(t.TEST("lambda('6/')(3) === 2")); 290 | eval(t.TEST("lambda('/')(6, 3) === 2")); 291 | eval(t.TEST("lambda('a, b -> a / b + 1')(6, 3) === 3")); 292 | eval(t.TEST("lambda('a / b + a')(6, 3) === 8")); 293 | eval(t.TEST("lambda('/2/')(6, 3) === 1")); 294 | eval(t.TEST("lambda('a -> b -> a / b + 1')(6)(3) === 3")); 295 | eval(t.TEST("lambda('-> 5')() === 5")); 296 | 297 | var f1 = lambda.build("a, b -> a + b + c").compile({c: 42}); 298 | eval(t.TEST("f1(1, 2) === 45")); 299 | 300 | var f2 = lambda.build("a + _ + b").compile({a: 13, b: 22}); 301 | eval(t.TEST("f2(3) === 38")); 302 | } 303 | ]); 304 | 305 | return {}; 306 | }); 307 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------