Skip to content

Instantly share code, notes, and snippets.

@miraclx
Created September 24, 2021 04:46
Show Gist options
  • Select an option

  • Save miraclx/4bc00883cf68fb1a80df5e105d9c616c to your computer and use it in GitHub Desktop.

Select an option

Save miraclx/4bc00883cf68fb1a80df5e105d9c616c to your computer and use it in GitHub Desktop.
JS TypedMatcher: Workaround to mimic Rust's `match` in JS
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]();
}
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