Skip to content

Instantly share code, notes, and snippets.

@seoh
Last active August 29, 2015 14:26
Show Gist options
  • Save seoh/41007ef9b0477cacad30 to your computer and use it in GitHub Desktop.
Save seoh/41007ef9b0477cacad30 to your computer and use it in GitHub Desktop.
Simple Monadic Parser using JavaScript
// https://www.cs.nott.ac.uk/~gmh/monparsing.pdf
//
// type Parser[T] = String -> [(T, String)]
//
/** lookahead token
*
* Parser -> Parser
*/
const ahead = p => (str) =>
p(str) ? ['', str] : [];
/** consume token
*
* Parser -> Parser
*/
const satisfy = p => (str) =>
p(str) ? [str[0], str.substr(1)] : [];
/** compose funtions, not used in this
*
* [(a -> a)] -> (a -> a)
*/
const compose = (...fns) => (arg) =>
fns.reverse().reduce((r,fn) => fn.apply(null, [r]), arg);
/** fallback
*
* (Parser, Parser) -> Parser
*/
const or = (pa, pb) => (str) => {
const r = pa(str);
if(r.length > 0) return r;
else return pb(str);
};
/** sequencial
*
* (Parser, Parser) -> Parser
*/
const and = (pa, pb) => (str) => {
const ra = pa(str);
if(ra.length === 0) return [];
const rb = pb(ra[1]);
if(rb.length === 0) return [];
return [ra[0] + rb[0], rb[1]];
};
/** monoid zero
*
* Parser
*/
const mzero = (str) => ['', str];
/** consume zero or more times token
*
* Parser -> Parser
*/
const many = (p) => (str) => {
const ra = p(str);
if(ra.length === 0) return ra;
const rb = or(many(p), mzero)(ra[1]);
return [ra[0] + rb[0], rb[1]];
};
//----------------------------------------------------------------------------//
const chr = ahead(str => str.length > 0);
const upper = and(chr, satisfy(ch => 'A' <= ch[0] && ch[0] <= 'Z'));
const lower = and(chr, satisfy(ch => 'a' <= ch[0] && ch[0] <= 'z'));
const digit = and(chr, satisfy(ch => '0' <= ch[0] && ch[0] <= '9'));
/**
* - Tokenizer
*
* atom = upper lower | upper
* amount = digit amount | digit | empty
*
*
* - Lexer
*
* mole = homo mole | mole
* homo = atom amount | atom
*
*/
const atom = or(and(upper, lower), upper);
const amount = many(digit);
const homo = or(and(atom, amount), atom);
const mole = many(homo);
const parse = (p) => (str) => or(p, mzero)(str)[0];
console.log(parse(mole)("H2O"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment