Skip to content

Instantly share code, notes, and snippets.

@natanbc
Last active March 9, 2019 15:55
Show Gist options
  • Save natanbc/198512eefed589439b0dbf40f36ae429 to your computer and use it in GitHub Desktop.
Save natanbc/198512eefed589439b0dbf40f36ae429 to your computer and use it in GitHub Desktop.
const defaultv = Symbol("default");
const extractor = Symbol("extractor");
const extract = function(as, opts) {
if(typeof as === "object") {
opts = as;
as = null;
}
const f = function(name, value, dest) {
if(opts && opts.validator) {
if(!opts.validator(value, name)) {
return false;
}
} else {
if(!value && (!opts || !opts.acceptAll)) {
return false;
}
}
const k = as || name;
if(typeof k !== "string") {
throw new Error("Cannot extract to non string key " + k);
}
dest[k] = value;
return true;
};
f[extractor] = true;
return f;
};
function matchPattern(pattern, value, name, extracted) {
if(pattern === defaultv) {
return true;
}
if(typeof pattern === "function" && pattern[extractor]) {
return pattern(name, value, extracted);
}
if(pattern === value) {
return true;
}
if(typeof pattern !== typeof value) {
return false;
}
if(Array.isArray(pattern)) {
if(!Array.isArray(value)) {
return false;
}
if(pattern.length !== value.length) {
return false;
}
for(let i = 0; i < pattern.length; i++) {
if(!matchPattern(pattern[i], value[i], i, extracted)) {
return false;
}
}
return true;
}
if(typeof pattern === "object") {
if(typeof value !== "object") {
return false;
}
for(const k of Object.getOwnPropertyNames(pattern)) {
if(!matchPattern(pattern[k], value[k], k, extracted)) {
return false;
}
}
return true;
}
return false;
}
function evalWithValues(values, code) {
let actualEval = "";
for(const k of Object.getOwnPropertyNames(values)) {
actualEval += "const " + k + " = values." + k + "\n";
}
actualEval += code;
return eval(actualEval);
}
function match(value) {
return function(cases, ...patterns) {
if((cases.length - 1) !== patterns.length) {
throw new Error("Cases and patterns must have the same length!");
}
for(let i = 0; i < cases.length; i++) {
const extracted = {};
if(matchPattern(patterns[i], value, null, extracted)) {
return evalWithValues(extracted, cases[i + 1]);
}
}
}
}
module.exports = {match, extract, defaultv};
const {match, extract, defaultv} = require("./pattern-match");
for(const a of [123, 1234, 12345]) {
console.log(match({a}) `
${{a: 123}} console.log("Matched {a: 123}");
${{a: 1234}} console.log("Matched {a: 1234}");
${{a: extract()}} console.log("Extracted variable: " + a);
${defaultv} console.log("Default case");
`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment