Last active
January 9, 2018 12:17
-
-
Save jooyunghan/d034e54130607154dd8dcb6f551fbcbd to your computer and use it in GitHub Desktop.
Parser using JSGenerators
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
// parser = string -> [match, remainder] | |
// read single item | |
function* item(s) { | |
if (s.length > 0) yield [s[0], s.slice(1)]; | |
} | |
function run(p, s) { | |
return [...p(s)] | |
} | |
// function char(c) { | |
// return function *(s) { | |
// for (const [a, rest] of item(s)) { | |
// if (a === c) { | |
// yield [c, rest]; | |
// } | |
// } | |
// } | |
// } | |
// function filter(pred, p) { | |
// return function*(s) { | |
// for (const [a, rest] of p(s)) { | |
// if (pred(a)) { | |
// yield [a, rest]; | |
// } | |
// } | |
// }; | |
// } | |
function* failure(s) { | |
return; | |
} | |
function filter(pred, p) { | |
return flatMap(a => (pred(a) ? success(a) : failure), p); | |
} | |
function char(c) { | |
return filter(a => a === c, item); | |
} | |
// function seq(p1, p2) { | |
// return function*(s) { | |
// for (const [a, rest1] of p1(s)) { | |
// for (const [b, rest2] of p2(rest1)) { | |
// yield [[a, b], rest2]; | |
// } | |
// } | |
// }; | |
// } | |
// function seq(p1, p2) { | |
// return flatMap(a => map(b => [a, b], p2), p1); | |
// } | |
function seq(...ps) { | |
return sequence(ps); | |
} | |
function sequence(ps) { | |
if (ps.length === 0) return success([]); | |
return flatMap(a => map(as => [a, ...as], sequence(ps.slice(1))), ps[0]); | |
} | |
function alt(p1, p2) { | |
return function* (s) { | |
yield* p1(s); | |
yield* p2(s); | |
}; | |
} | |
function many(p) { | |
return alt(success([]), defer(() => many1(p))); | |
} | |
function success(v) { | |
return function* (s) { | |
yield [v, s]; | |
}; | |
} | |
function many1(p) { | |
return map(([a, as]) => [a, ...as], seq(p, many(p))); | |
} | |
// function map(f, p) { | |
// return function*(s) { | |
// for (const [a, rest] of p(s)) { | |
// yield [f(a), rest]; | |
// } | |
// }; | |
// } | |
function map(f, p) { | |
return flatMap(a => success(f(a)), p); | |
} | |
function flatMap(f, p) { | |
return function* (s) { | |
for (const [a, rest] of p(s)) { | |
yield* f(a)(rest); | |
} | |
}; | |
} | |
function defer(pf) { | |
return function* (s) { | |
yield* pf()(s); | |
}; | |
} | |
// function wrap(body, p, s) { | |
// return seq(char(p), seq(body, char(s))); | |
// } | |
function wrap(body, p, s) { | |
return seq(char(p), body, char(s)); | |
} | |
const parens = many(defer(() => paren)); | |
const p1 = wrap(parens, "(", ")"); | |
const p2 = wrap(parens, "[", "]"); | |
const p3 = wrap(parens, "{", "}"); | |
const paren = alt(p1, alt(p2, p3)); | |
function isValid(s) { | |
for (const [a, rest] of parens(s)) { | |
if (rest === "") return true; | |
} | |
return false; | |
} | |
console.log(isValid("{}")); | |
console.log(isValid("()[]{}()")); | |
console.log(isValid("[()]")); | |
console.log(isValid("[(][)]")); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment