Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Build a parser combinator step by step
// Error handling helper
const ok = (found, remain) => ({ found, remain });
const error = (msg) => ({ error: msg });
// Primitive parsers
const digit = (input) => {
const [head, ...rest] = input;
if (!isNaN(+head) && +head >= 0 && +head <= 9) {
return ok(head, rest);
} else {
return error(`Expected a digit, found '${head}'`);
}
}
const letter = (input) => {
const [head, ...rest] = input;
if (head.match(/[a-zA-Z]/) !== null) {
return ok(head, rest);
} else {
return error(`Expected a letter, found '${head}'`);
}
};
const char = (expected) => (input) => {
const [head, ...rest] = input;
if (head === expected) {
return ok(head, rest);
} else {
return error(`Expected '${expected}', found '${head}'`);
}
};
// Combinators
const or = (...parsers) => {
return (input) => {
for (let parser of parsers) {
const ret = parser(input);
if (ret.error) continue;
return ret;
}
return error('Could not parsed the given input');
};
};
const match = (parsers, fn) => {
return (input) => {
let remain = input;
let results = [];
for (let parser of parsers) {
const ret = parser(remain);
if (ret.error) return ret;
remain = ret.remain;
results.push(ret.found);
}
return ok(fn(...results), remain);
}
};
// Combined parsers
const digitOrLetter = or(digit, letter);
const colorCode = match([digitOrLetter, digitOrLetter], (first, second) => `${first}${second}`);
const hexColor = match([char('#'), colorCode, colorCode, colorCode], (_, red, green, blue) => {
return { red, green, blue };
});
// Try it out
const test = "#f5b2c5";
const result = hexColor(test);
debug(result.found);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.