Skip to content

Instantly share code, notes, and snippets.

@Hypercubed
Last active February 6, 2016 10:30
Show Gist options
  • Save Hypercubed/befa878a2b75fd878c5e to your computer and use it in GitHub Desktop.
Save Hypercubed/befa878a2b75fd878c5e to your computer and use it in GitHub Desktop.
requirebin sketch
var typed = require("typed-function");
typed.addType({
name: 'zero',
test: function (x) { return x === 0; }
});
typed.addType({
name: 'one',
test: function (x) { return x === 1; }
});
const fib = typed({
'zero': function (n) { return 0 },
'one': function (n) { return 1 },
'any': function (n) { return fib(n - 1) + fib(n - 2); }
});
document.body.innerHTML =
new Array(20).fill().map(function (x,i) { return fib(i); });
require=function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}({"typed-function":[function(require,module,exports){"use strict";(function(factory){if(typeof define==="function"&&define.amd){define([],factory)}else if(typeof exports==="object"){module.exports=factory()}else{window.typed=factory()}})(function(){function create(){function getTypeTest(name){var test;for(var i=0;i<typed.types.length;i++){var entry=typed.types[i];if(entry.name===name){test=entry.test;break}}if(!test){var hint;for(i=0;i<typed.types.length;i++){entry=typed.types[i];if(entry.name.toLowerCase()==name.toLowerCase()){hint=entry.name;break}}throw new Error('Unknown type "'+name+'"'+(hint?'. Did you mean "'+hint+'"?':""))}return test}function getName(fns){var name="";for(var i=0;i<fns.length;i++){var fn=fns[i];if(fn.name!=""){if(name==""){name=fn.name}else if(name!=fn.name){var err=new Error("Function names do not match (expected: "+name+", actual: "+fn.name+")");err.data={actual:fn.name,expected:name};throw err}}}return name}function createError(fn,argCount,index,actual,expected){var actualType=getTypeOf(actual);var _expected=expected?expected.split(","):null;var _fn=fn||"unnamed";var anyType=_expected&&contains(_expected,"any");var message;var data={fn:fn,index:index,actual:actual,expected:_expected};if(_expected){if(argCount>index&&!anyType){message="Unexpected type of argument in function "+_fn+" (expected: "+_expected.join(" or ")+", actual: "+actualType+", index: "+index+")"}else{message="Too few arguments in function "+_fn+" (expected: "+_expected.join(" or ")+", index: "+index+")"}}else{message="Too many arguments in function "+_fn+" (expected: "+index+", actual: "+argCount+")"}var err=new TypeError(message);err.data=data;return err}function Refs(name){this.name=name||"refs";this.categories={}}Refs.prototype.add=function(fn,category){var cat=category||"fn";if(!this.categories[cat])this.categories[cat]=[];var index=this.categories[cat].indexOf(fn);if(index==-1){index=this.categories[cat].length;this.categories[cat].push(fn)}return cat+index};Refs.prototype.toCode=function(){var code=[];var path=this.name+".categories";var categories=this.categories;for(var cat in categories){if(categories.hasOwnProperty(cat)){var category=categories[cat];for(var i=0;i<category.length;i++){code.push("var "+cat+i+" = "+path+"['"+cat+"']["+i+"];")}}}return code.join("\n")};function Param(types,varArgs){if(typeof types==="string"){var _types=types.trim();var _varArgs=_types.substr(0,3)==="...";if(_varArgs){_types=_types.substr(3)}if(_types===""){this.types=["any"]}else{this.types=_types.split("|");for(var i=0;i<this.types.length;i++){this.types[i]=this.types[i].trim()}}}else if(Array.isArray(types)){this.types=types}else if(types instanceof Param){return types.clone()}else{throw new Error("String or Array expected")}this.conversions=[];this.varArgs=_varArgs||varArgs||false;this.anyType=this.types.indexOf("any")!==-1}Param.compare=function(a,b){if(a.anyType)return 1;if(b.anyType)return-1;if(contains(a.types,"Object"))return 1;if(contains(b.types,"Object"))return-1;if(a.hasConversions()){if(b.hasConversions()){var i,ac,bc;for(i=0;i<a.conversions.length;i++){if(a.conversions[i]!==undefined){ac=a.conversions[i];break}}for(i=0;i<b.conversions.length;i++){if(b.conversions[i]!==undefined){bc=b.conversions[i];break}}return typed.conversions.indexOf(ac)-typed.conversions.indexOf(bc)}else{return 1}}else{if(b.hasConversions()){return-1}else{var ai,bi;for(i=0;i<typed.types.length;i++){if(typed.types[i].name===a.types[0]){ai=i;break}}for(i=0;i<typed.types.length;i++){if(typed.types[i].name===b.types[0]){bi=i;break}}return ai-bi}}};Param.prototype.overlapping=function(other){for(var i=0;i<this.types.length;i++){if(contains(other.types,this.types[i])){return true}}return false};Param.prototype.clone=function(){var param=new Param(this.types.slice(),this.varArgs);param.conversions=this.conversions.slice();return param};Param.prototype.hasConversions=function(){return this.conversions.length>0};Param.prototype.contains=function(types){for(var i=0;i<this.types.length;i++){if(types[this.types[i]]){return true}}return false};Param.prototype.toString=function(toConversion){var types=[];var keys={};for(var i=0;i<this.types.length;i++){var conversion=this.conversions[i];var type=toConversion&&conversion?conversion.to:this.types[i];if(!(type in keys)){keys[type]=true;types.push(type)}}return(this.varArgs?"...":"")+types.join("|")};function Signature(params,fn){var _params;if(typeof params==="string"){_params=params!==""?params.split(","):[]}else if(Array.isArray(params)){_params=params}else{throw new Error("string or Array expected")}this.params=new Array(_params.length);for(var i=0;i<_params.length;i++){var param=new Param(_params[i]);this.params[i]=param;if(i===_params.length-1){this.varArgs=param.varArgs}else{if(param.varArgs){throw new SyntaxError('Unexpected variable arguments operator "..."')}}}this.fn=fn}Signature.prototype.clone=function(){return new Signature(this.params.slice(),this.fn)};Signature.prototype.expand=function(){var signatures=[];function recurse(signature,path){if(path.length<signature.params.length){var i,newParam,conversion;var param=signature.params[path.length];if(param.varArgs){newParam=param.clone();for(i=0;i<typed.conversions.length;i++){conversion=typed.conversions[i];if(!contains(param.types,conversion.from)&&contains(param.types,conversion.to)){var j=newParam.types.length;newParam.types[j]=conversion.from;newParam.conversions[j]=conversion}}recurse(signature,path.concat(newParam))}else{for(i=0;i<param.types.length;i++){recurse(signature,path.concat(new Param(param.types[i])))}for(i=0;i<typed.conversions.length;i++){conversion=typed.conversions[i];if(!contains(param.types,conversion.from)&&contains(param.types,conversion.to)){newParam=new Param(conversion.from);newParam.conversions[0]=conversion;recurse(signature,path.concat(newParam))}}}}else{signatures.push(new Signature(path,signature.fn))}}recurse(this,[]);return signatures};Signature.compare=function(a,b){if(a.params.length>b.params.length)return 1;if(a.params.length<b.params.length)return-1;var i;var len=a.params.length;var ac=0;var bc=0;for(i=0;i<len;i++){if(a.params[i].hasConversions())ac++;if(b.params[i].hasConversions())bc++}if(ac>bc)return 1;if(ac<bc)return-1;for(i=0;i<a.params.length;i++){var cmp=Param.compare(a.params[i],b.params[i]);if(cmp!==0){return cmp}}return 0};Signature.prototype.hasConversions=function(){for(var i=0;i<this.params.length;i++){if(this.params[i].hasConversions()){return true}}return false};Signature.prototype.ignore=function(){var types={};for(var i=0;i<typed.ignore.length;i++){types[typed.ignore[i]]=true}for(i=0;i<this.params.length;i++){if(this.params[i].contains(types)){return true}}return false};Signature.prototype.toCode=function(refs,prefix){var code=[];var args=new Array(this.params.length);for(var i=0;i<this.params.length;i++){var param=this.params[i];var conversion=param.conversions[0];if(param.varArgs){args[i]="varArgs"}else if(conversion){args[i]=refs.add(conversion.convert,"convert")+"(arg"+i+")"}else{args[i]="arg"+i}}var ref=this.fn?refs.add(this.fn,"signature"):undefined;if(ref){return prefix+"return "+ref+"("+args.join(", ")+"); // signature: "+this.params.join(", ")}return code.join("\n")};Signature.prototype.toString=function(){return this.params.join(", ")};function Node(path,signature,childs){this.path=path||[];this.param=path[path.length-1]||null;this.signature=signature||null;this.childs=childs||[]}Node.prototype.toCode=function(refs,prefix,anyType){var code=[];if(this.param){var index=this.path.length-1;var conversion=this.param.conversions[0];var comment="// type: "+(conversion?conversion.from+" (convert to "+conversion.to+")":this.param);if(this.param.varArgs){if(this.param.anyType){code.push(prefix+"if (arguments.length > "+index+") {");code.push(prefix+" var varArgs = [];");code.push(prefix+" for (var i = "+index+"; i < arguments.length; i++) {");code.push(prefix+" varArgs.push(arguments[i]);");code.push(prefix+" }");code.push(this.signature.toCode(refs,prefix+" "));code.push(prefix+"}")}else{var getTests=function(types,arg){var tests=[];for(var i=0;i<types.length;i++){tests[i]=refs.add(getTypeTest(types[i]),"test")+"("+arg+")"}return tests.join(" || ")}.bind(this);var allTypes=this.param.types;var exactTypes=[];for(var i=0;i<allTypes.length;i++){if(this.param.conversions[i]===undefined){exactTypes.push(allTypes[i])}}code.push(prefix+"if ("+getTests(allTypes,"arg"+index)+") { "+comment);code.push(prefix+" var varArgs = [arg"+index+"];");code.push(prefix+" for (var i = "+(index+1)+"; i < arguments.length; i++) {");code.push(prefix+" if ("+getTests(exactTypes,"arguments[i]")+") {");code.push(prefix+" varArgs.push(arguments[i]);");for(var i=0;i<allTypes.length;i++){var conversion_i=this.param.conversions[i];if(conversion_i){var test=refs.add(getTypeTest(allTypes[i]),"test");var convert=refs.add(conversion_i.convert,"convert");code.push(prefix+" }");code.push(prefix+" else if ("+test+"(arguments[i])) {");code.push(prefix+" varArgs.push("+convert+"(arguments[i]));")}}code.push(prefix+" } else {");code.push(prefix+" throw createError(name, arguments.length, i, arguments[i], '"+exactTypes.join(",")+"');");code.push(prefix+" }");code.push(prefix+" }");code.push(this.signature.toCode(refs,prefix+" "));code.push(prefix+"}")}}else{if(this.param.anyType){code.push(prefix+"// type: any");code.push(this._innerCode(refs,prefix,anyType))}else{var type=this.param.types[0];var test=type!=="any"?refs.add(getTypeTest(type),"test"):null;code.push(prefix+"if ("+test+"(arg"+index+")) { "+comment);code.push(this._innerCode(refs,prefix+" ",anyType));code.push(prefix+"}")}}}else{code.push(this._innerCode(refs,prefix,anyType))}return code.join("\n")};Node.prototype._innerCode=function(refs,prefix,anyType){var code=[];var i;if(this.signature){code.push(prefix+"if (arguments.length === "+this.path.length+") {");code.push(this.signature.toCode(refs,prefix+" "));code.push(prefix+"}")}var nextAnyType;for(i=0;i<this.childs.length;i++){if(this.childs[i].param.anyType){nextAnyType=this.childs[i];break}}for(i=0;i<this.childs.length;i++){code.push(this.childs[i].toCode(refs,prefix,nextAnyType))}if(anyType&&!this.param.anyType){code.push(anyType.toCode(refs,prefix,nextAnyType))}var exceptions=this._exceptions(refs,prefix);if(exceptions){code.push(exceptions)}return code.join("\n")};Node.prototype._exceptions=function(refs,prefix){var index=this.path.length;if(this.childs.length===0){return[prefix+"if (arguments.length > "+index+") {",prefix+" throw createError(name, arguments.length, "+index+", arguments["+index+"]);",prefix+"}"].join("\n")}else{var keys={};var types=[];for(var i=0;i<this.childs.length;i++){var node=this.childs[i];if(node.param){for(var j=0;j<node.param.types.length;j++){var type=node.param.types[j];if(!(type in keys)&&!node.param.conversions[j]){keys[type]=true;types.push(type)}}}}return prefix+"throw createError(name, arguments.length, "+index+", arguments["+index+"], '"+types.join(",")+"');"}};function parseSignatures(rawSignatures){var signature;var keys={};var signatures=[];var i;for(var types in rawSignatures){if(rawSignatures.hasOwnProperty(types)){var fn=rawSignatures[types];signature=new Signature(types,fn);if(signature.ignore()){continue}var expanded=signature.expand();for(i=0;i<expanded.length;i++){var signature_i=expanded[i];var key=signature_i.toString();var existing=keys[key];if(!existing){keys[key]=signature_i}else{var cmp=Signature.compare(signature_i,existing);if(cmp<0){keys[key]=signature_i}else if(cmp===0){throw new Error('Signature "'+key+'" is defined twice')}}}}}for(key in keys){if(keys.hasOwnProperty(key)){signatures.push(keys[key])}}signatures.sort(function(a,b){return Signature.compare(a,b)});for(i=0;i<signatures.length;i++){signature=signatures[i];if(signature.varArgs){var index=signature.params.length-1;var param=signature.params[index];var t=0;while(t<param.types.length){if(param.conversions[t]){var type=param.types[t];for(var j=0;j<signatures.length;j++){var other=signatures[j];var p=other.params[index];if(other!==signature&&p&&contains(p.types,type)&&!p.conversions[index]){param.types.splice(t,1);param.conversions.splice(t,1);t--;break}}}t++}}}return signatures}function mapSignatures(signatures){var normalized={};for(var i=0;i<signatures.length;i++){var signature=signatures[i];if(signature.fn&&!signature.hasConversions()){var params=signature.params.join(",");normalized[params]=signature.fn}}return normalized}function parseTree(signatures,path){var i,signature;var index=path.length;var nodeSignature;var filtered=[];for(i=0;i<signatures.length;i++){signature=signatures[i];if(signature.params.length===index&&!nodeSignature){nodeSignature=signature}if(signature.params[index]!=undefined){filtered.push(signature)}}filtered.sort(function(a,b){return Param.compare(a.params[index],b.params[index])});var entries=[];for(i=0;i<filtered.length;i++){signature=filtered[i];var param=signature.params[index];var existing=entries.filter(function(entry){return entry.param.overlapping(param)})[0];if(existing){if(existing.param.varArgs){throw new Error('Conflicting types "'+existing.param+'" and "'+param+'"')}existing.signatures.push(signature)}else{entries.push({param:param,signatures:[signature]})}}var childs=new Array(entries.length);for(i=0;i<entries.length;i++){var entry=entries[i];childs[i]=parseTree(entry.signatures,path.concat(entry.param))}return new Node(path,nodeSignature,childs)}function getArgs(count){var args=[];for(var i=0;i<count;i++){args[i]="arg"+i}return args}function _typed(name,signatures){var refs=new Refs;var _signatures=parseSignatures(signatures);if(_signatures.length==0){throw new Error("No signatures provided")}var node=parseTree(_signatures,[]);var code=[];var _name=name||"";var _args=getArgs(maxParams(_signatures));code.push("function "+_name+"("+_args.join(", ")+") {");code.push(' "use strict";');code.push(" var name = '"+_name+"';");code.push(node.toCode(refs," "));code.push("}");var body=[refs.toCode(),"return "+code.join("\n")].join("\n");var factory=new Function(refs.name,"createError",body);var fn=factory(refs,createError);fn.signatures=mapSignatures(_signatures);return fn}function maxParams(signatures){var max=0;for(var i=0;i<signatures.length;i++){var len=signatures[i].params.length;if(len>max){max=len}}return max}function getTypeOf(x){var obj;for(var i=0;i<typed.types.length;i++){var entry=typed.types[i];if(entry.name==="Object"){obj=entry}else{if(entry.test(x))return entry.name}}if(obj&&obj.test(x))return obj.name;return"unknown"}function contains(array,entry){return array.indexOf(entry)!==-1}var types=[{name:"number",test:function(x){return typeof x==="number"}},{name:"string",test:function(x){return typeof x==="string"}},{name:"boolean",test:function(x){return typeof x==="boolean"}},{name:"Function",test:function(x){return typeof x==="function"}},{name:"Array",test:Array.isArray},{name:"Date",test:function(x){return x instanceof Date}},{name:"RegExp",test:function(x){return x instanceof RegExp}},{name:"Object",test:function(x){return typeof x==="object"}},{name:"null",test:function(x){return x===null}},{name:"undefined",test:function(x){return x===undefined}}];var config={};var conversions=[];var ignore=[];var typed={config:config,types:types,conversions:conversions,ignore:ignore};typed=_typed("typed",{Object:function(signatures){var fns=[];for(var signature in signatures){if(signatures.hasOwnProperty(signature)){fns.push(signatures[signature])}}var name=getName(fns);return _typed(name,signatures)},"string, Object":_typed,"...Function":function(fns){var err;var name=getName(fns);var signatures={};for(var i=0;i<fns.length;i++){var fn=fns[i];if(!(typeof fn.signatures==="object")){err=new TypeError("Function is no typed-function (index: "+i+")");err.data={index:i};throw err}for(var signature in fn.signatures){if(fn.signatures.hasOwnProperty(signature)){if(signatures.hasOwnProperty(signature)){if(fn.signatures[signature]!==signatures[signature]){err=new Error('Signature "'+signature+'" is defined twice');err.data={signature:signature};throw err}}else{signatures[signature]=fn.signatures[signature]}}}}return _typed(name,signatures)}});function find(fn,signature){if(!fn.signatures){throw new TypeError("Function is no typed-function")}var arr;if(typeof signature==="string"){arr=signature.split(",");for(var i=0;i<arr.length;i++){arr[i]=arr[i].trim()}}else if(Array.isArray(signature)){arr=signature}else{throw new TypeError("String array or a comma separated string expected")}var str=arr.join(",");var match=fn.signatures[str];if(match){return match}throw new TypeError("Signature not found (signature: "+(fn.name||"unnamed")+"("+arr.join(", ")+"))")}function convert(value,type){var from=getTypeOf(value);if(type===from){return value}for(var i=0;i<typed.conversions.length;i++){var conversion=typed.conversions[i];if(conversion.from===from&&conversion.to===type){return conversion.convert(value)}}throw new Error("Cannot convert from "+from+" to "+type)}typed.config=config;typed.types=types;typed.conversions=conversions;typed.ignore=ignore;typed.create=create;typed.find=find;typed.convert=convert;typed.addType=function(type){if(!type||typeof type.name!=="string"||typeof type.test!=="function"){throw new TypeError("Object with properties {name: string, test: function} expected")}typed.types.push(type)};typed.addConversion=function(conversion){if(!conversion||typeof conversion.from!=="string"||typeof conversion.to!=="string"||typeof conversion.convert!=="function"){throw new TypeError("Object with properties {from: string, to: string, convert: function} expected")}typed.conversions.push(conversion)};return typed}return create()})},{}]},{},[]);var typed=require("typed-function");typed.addType({name:"zero",test:function(x){return x===0}});typed.addType({name:"one",test:function(x){return x===1}});const fib=typed({zero:function(n){return 0},one:function(n){return 1},any:function(n){return fib(n-1)+fib(n-2)}});document.body.innerHTML=new Array(20).fill().map(function(x,i){return fib(i)});
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"typed-function": "0.10.3"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- contents of this file will be placed inside the <head> -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment