Last active
January 19, 2022 14:58
-
-
Save ruiramos/d1af3dfbf640e953c87447b33b272150 to your computer and use it in GitHub Desktop.
Simple Javascript pattern matching
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let a = [null, {status: 'OK'}]; | |
switch_( | |
(err, _) => console.log('error', err), | |
(_, resp) => console.log('response', resp) | |
)(a); | |
// logs 'response' { "status": "OK" } | |
let b = [{err: 401}, null]; | |
switch_( | |
(err, _) => console.log('error', err), | |
(_, resp) => console.log('response', resp) | |
)(b); | |
// logs 'error' { "err": 401 } | |
let c = [1, 2, 3, 4]; | |
let sumReduce = numbers => switch_( | |
(x, $tail) => x + sumReduce($tail), | |
(x) => x | |
)(numbers); | |
console.log(sumReduce(c)); // 10 | |
let len = array => switch_( | |
(a, b, c) => 3, | |
(a, b) => 2, | |
(a) => 1, | |
() => 'dont know' | |
)(array); | |
console.log(len([9,9,9,9,9,9])) // 'dont know' | |
let players = switch_( | |
({pool}) => `${pool} plays pool`, | |
({darts}) => `${darts} plays darts`, | |
() => 'none' | |
); | |
console.log(players({darts: 'David'})); // David plays darts | |
console.log(players({pool: 'Paul'})); // Paul plays pool | |
let guess = switch_( | |
(n = 1) => 'very low: ' + n, | |
(n = 2) => 'low: ' + n, | |
(n = 3) => 'almost: ' + n, | |
(n = 4) => 'just right: ' + n, | |
(n) => 'give up: ' + n | |
); | |
console.log(guess(4)); // just right: 4 | |
let guessHarder = switch_( | |
(n = 3, p = 2) => 'WINNER!!!', | |
(a, b) => 'try again', | |
() => 'guess 2 numbers' | |
); | |
console.log(guessHarder([4, 2])); // try again | |
//--- | |
function switch_(...exps){ | |
return function(data = []){ | |
if(!Array.isArray(data)) data = [data]; | |
for(let i = 0; i < exps.length; i++){ | |
let exp = exps[i]; | |
var args = exp | |
.toString() | |
.match(/(?:function\s)?.*?\(([^)]*)\)/)[1] | |
.split(','); | |
let argValues = []; | |
let usesTail = false; | |
for(let j = 0; j < args.length; j++){ | |
let arg = args[j].trim(); | |
if(arg === '_'){ | |
argValues[j] = null; | |
continue; | |
} | |
if(!data[j]) break; | |
if(arg.indexOf('$') === 0) { | |
argValues[j] = data.slice(j); | |
usesTail = true; | |
break; | |
} else if(arg.match(/{\w+}/)){ | |
let name = (arg.match(/(\w+)/))[1]; | |
let result = eval_(data[j], name); | |
if(result){ | |
argValues[j] = {[name]: result}; | |
} else break; | |
} else if(arg.indexOf('=') > -1){ | |
let [ref, val] = arg.split('='); | |
ref = ref.trim(); | |
val = val.trim(); | |
let result = data[j] == val; | |
if(result){ | |
argValues[j] = val; | |
} else break; | |
} else { | |
argValues[j] = data[j]; | |
} | |
} | |
if(( | |
// common case where number of params and args match | |
argValues.length === data.length && | |
argValues.length === args.length | |
) || ( | |
// empty catch all | |
args.length === 1 && | |
args[0] === "" | |
) || | |
// $tail special case | |
usesTail | |
){ | |
return exp.apply(null, argValues); | |
} | |
} | |
} | |
} | |
function eval_(ctx, obj){ | |
try{ | |
return new Function(`return ${obj}`).call(ctx); | |
} catch(e){ | |
return new Function(`return this.${obj}`).call(ctx); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment