Created
July 24, 2020 05:00
-
-
Save huytd/636733ebc54b4fe3658fab795757342f to your computer and use it in GitHub Desktop.
Build a parser combinator step by step
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
// 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