Created
September 24, 2021 04:46
-
-
Save miraclx/4bc00883cf68fb1a80df5e105d9c616c to your computer and use it in GitHub Desktop.
JS TypedMatcher: Workaround to mimic Rust's `match` in JS
This file contains hidden or 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
| export async function typedMatcher(val, handler) { | |
| let register = {}; | |
| let value = valueSpec => { | |
| let data, matchEntry; | |
| register[(matchEntry = Object.assign(Symbol("matchEntry")))] = data = {0: valueSpec}; | |
| matchEntry.type = type => ((data._ = type), matchEntry); | |
| return matchEntry; | |
| }; | |
| let type = typeSpec => { | |
| let data, matchEntry; | |
| register[(matchEntry = Object.assign(Symbol("matchEntry")))] = data = {_: typeSpec}; | |
| matchEntry.value = valueSpec => ((data[0] = valueSpec), matchEntry); | |
| return matchEntry; | |
| }; | |
| let [none, one] = [Symbol("NoneMatched"), Symbol("OneMatched")]; | |
| let rawMatches = handler({value, type, none, one}); | |
| let matches = Object.getOwnPropertySymbols(register) | |
| .filter(entry => !(entry === none || entry === one)) | |
| .map(entry => ({...register[entry], $: rawMatches[entry]})); | |
| for (let matchSpec of matches) { | |
| if (typeof matchSpec === "function") return matchSpec(val); | |
| let hasValidated = 0; | |
| if ("_" in matchSpec) { | |
| let {_: typeSpec} = matchSpec; | |
| if (typeSpec.constructor === Object && Object.entries(typeSpec).every(([key, type]) => val[key].constructor === type)); | |
| else if (Array.isArray(typeSpec) && typeSpec.every((type, i) => type === undefined || val[i].constructor === type)); | |
| else if (val.constructor !== typeSpec) continue; | |
| hasValidated |= 1; | |
| } | |
| if ("0" in matchSpec) { | |
| let {0: data} = matchSpec; | |
| if (typeof data === "function") { | |
| if (!(await data(val))) continue; | |
| } else if (data.constructor === Object && Object.entries(data).every(([key, value]) => val[key] === value)); | |
| else if (Array.isArray(data) && data.every((value, i) => value === undefined || val[i] === value)); | |
| else if (val !== data) continue; | |
| hasValidated |= 1; | |
| } | |
| if (!hasValidated) continue; | |
| let result = typeof matchSpec.$ === "function" ? matchSpec.$(val) : matchSpec.$; | |
| if (one in rawMatches) rawMatches[one](); | |
| return result; | |
| } | |
| if (none in rawMatches) rawMatches[none](); | |
| } |
This file contains hidden or 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
| import { typedMatcher } from "./insanity.js" | |
| function main() { | |
| typedMatcher(["Hello", 5073, true], ({type, value, none, one}) => ({ | |
| [type([, , Number])]: ([, , val]) => console.log(`Your number, plus 50 is.. ${val + 50}`), | |
| [type(String)]: () => console.log(`I'm not listening`), | |
| [type([, Number, Boolean]).value(([, val]) => val === 5073)]: () => console.log("Correct"), | |
| [value(["Hello", , true])]: () => console.log("also correct?"), | |
| [none]: () => console.log(`try again`), | |
| [one]: () => console.log("we matched at least one of these"), | |
| })); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment