Last active
March 9, 2019 15:55
-
-
Save natanbc/198512eefed589439b0dbf40f36ae429 to your computer and use it in GitHub Desktop.
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
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}; |
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
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