Created
March 31, 2017 03:05
-
-
Save JohnEarnest/19f13638949ea86e47e3a199434a7677 to your computer and use it in GitHub Desktop.
A compact set of PEG parser combinators in ES6.
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
// PEG parser combinators | |
const lookup = x => typeof x == 'string' ? eval(x) : x | |
const match = (x, y, z) => x ? { c:y, v:z } : { e: true } | |
const eof = s => match(s.length, 0, '') | |
const char = s => match(s.length, 1, s[0]) | |
const not = g => s => match(g(s).e, 0, '') | |
const has = g => s => match(!g(s).e, 0, '') | |
const oneof = t => s => match(t.indexOf(s[0]) >= 0, 1, s[0]) | |
const lit = t => s => match(!s.indexOf(t), t.length, t) | |
const option = g => choose(g, lit('')) | |
const prod = (g, f) => s => (r => r.e ? r : { c:r.c, v:f(r.v) })(g(s)) | |
const choose = (...a) => s => a.reduce((x, y) => x.e ? y(s) : x, { e: true }) | |
const seq = (...a) => s => a.reduce(function(x, y) { | |
var r = x.e ? x : lookup(y)(s.slice(x.c)) | |
return r.e ? r : { c:x.c+r.c, v:x.v.concat([r.v]) } | |
}, { c:0, v:[] }) | |
// usage example: | |
const noun = oneof('abcdefghijklmnopqrstuvwxyz') | |
const xcolon = x => prod(seq(oneof(x), option(lit(':'))), x => x.join('')) | |
const verb = xcolon('+-*%!&|<>=~,^#_$?@.') | |
const adverb = xcolon('\'\\/') | |
const term = choose(prod(seq(lit('('), 'kexpr', lit(')')), x => x[1]), noun) | |
const kexpr = choose( | |
prod(seq(term, adverb, 'kexpr'), x => [x[1], x[0], x[2]]), | |
prod(seq(term, verb, 'kexpr'), x => [x[1], x[0], x[2]]), | |
seq(adverb, 'kexpr'), | |
seq(verb, 'kexpr'), | |
term | |
) | |
const test = x => console.log(JSON.stringify(x.v)) | |
test(kexpr('+b')) | |
test(kexpr('a+b')) | |
test(kexpr('(a+b)*c')) | |
test(kexpr('a+b*c')) | |
test(kexpr('f/b+c')) | |
test(kexpr('a+f/b+c')) | |
test(kexpr('(a+f)/b+c')) | |
test(kexpr('a+f/*:\'z-w')) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment